Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpproto.c @ 1d7d9935

History | View | Annotate | Download (7.88 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
#include "avformat.h"
22

    
23
#include <unistd.h>
24
#include <stdarg.h>
25
#include "network.h"
26
#include <fcntl.h>
27

    
28
#define RTP_TX_BUF_SIZE  (64 * 1024)
29
#define RTP_RX_BUF_SIZE  (128 * 1024)
30

    
31
typedef struct RTPContext {
32
    URLContext *rtp_hd, *rtcp_hd;
33
    int rtp_fd, rtcp_fd;
34
} RTPContext;
35

    
36
/**
37
 * If no filename is given to av_open_input_file because you want to
38
 * get the local port first, then you must call this function to set
39
 * the remote server address.
40
 *
41
 * @param s1 media file context
42
 * @param uri of the remote server
43
 * @return zero if no error.
44
 */
45
int rtp_set_remote_url(URLContext *h, const char *uri)
46
{
47
    RTPContext *s = h->priv_data;
48
    char hostname[256];
49
    int port;
50

    
51
    char buf[1024];
52
    char path[1024];
53

    
54
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
55
              path, sizeof(path), uri);
56

    
57
    snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path);
58
    udp_set_remote_url(s->rtp_hd, buf);
59

    
60
    snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path);
61
    udp_set_remote_url(s->rtcp_hd, buf);
62
    return 0;
63
}
64

    
65

    
66
/* add option to url of the form:
67
   "http://host:port/path?option1=val1&option2=val2... */
68
static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
69
{
70
    char buf1[1024];
71
    va_list ap;
72

    
73
    va_start(ap, fmt);
74
    if (strchr(buf, '?'))
75
        pstrcat(buf, buf_size, "&");
76
    else
77
        pstrcat(buf, buf_size, "?");
78
    vsnprintf(buf1, sizeof(buf1), fmt, ap);
79
    pstrcat(buf, buf_size, buf1);
80
    va_end(ap);
81
}
82

    
83
static void build_udp_url(char *buf, int buf_size,
84
                          const char *hostname, int port,
85
                          int local_port, int multicast, int ttl)
86
{
87
    snprintf(buf, buf_size, "udp://%s:%d", hostname, port);
88
    if (local_port >= 0)
89
        url_add_option(buf, buf_size, "localport=%d", local_port);
90
    if (multicast)
91
        url_add_option(buf, buf_size, "multicast=1", multicast);
92
    if (ttl >= 0)
93
        url_add_option(buf, buf_size, "ttl=%d", ttl);
94
}
95

    
96
/*
97
 * url syntax: rtp://host:port[?option=val...]
98
 * option: 'multicast=1' : enable multicast
99
 *         'ttl=n'       : set the ttl value (for multicast only)
100
 *         'localport=n' : set the local port to n
101
 *
102
 */
103
static int rtp_open(URLContext *h, const char *uri, int flags)
104
{
105
    RTPContext *s;
106
    int port, is_output, is_multicast, ttl, local_port;
107
    char hostname[256];
108
    char buf[1024];
109
    char path[1024];
110
    const char *p;
111

    
112
    is_output = (flags & URL_WRONLY);
113

    
114
    s = av_mallocz(sizeof(RTPContext));
115
    if (!s)
116
        return -ENOMEM;
117
    h->priv_data = s;
118

    
119
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
120
              path, sizeof(path), uri);
121
    /* extract parameters */
122
    is_multicast = 0;
123
    ttl = -1;
124
    local_port = -1;
125
    p = strchr(uri, '?');
126
    if (p) {
127
        is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p);
128
        if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
129
            ttl = strtol(buf, NULL, 10);
130
        }
131
        if (find_info_tag(buf, sizeof(buf), "localport", p)) {
132
            local_port = strtol(buf, NULL, 10);
133
        }
134
    }
135

    
136
    build_udp_url(buf, sizeof(buf),
137
                  hostname, port, local_port, is_multicast, ttl);
138
    if (url_open(&s->rtp_hd, buf, flags) < 0)
139
        goto fail;
140
    local_port = udp_get_local_port(s->rtp_hd);
141
    /* XXX: need to open another connexion if the port is not even */
142

    
143
    /* well, should suppress localport in path */
144

    
145
    build_udp_url(buf, sizeof(buf),
146
                  hostname, port + 1, local_port + 1, is_multicast, ttl);
147
    if (url_open(&s->rtcp_hd, buf, flags) < 0)
148
        goto fail;
149

    
150
    /* just to ease handle access. XXX: need to suppress direct handle
151
       access */
152
    s->rtp_fd = udp_get_file_handle(s->rtp_hd);
153
    s->rtcp_fd = udp_get_file_handle(s->rtcp_hd);
154

    
155
    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
156
    h->is_streamed = 1;
157
    return 0;
158

    
159
 fail:
160
    if (s->rtp_hd)
161
        url_close(s->rtp_hd);
162
    if (s->rtcp_hd)
163
        url_close(s->rtcp_hd);
164
    av_free(s);
165
    return AVERROR_IO;
166
}
167

    
168
static int rtp_read(URLContext *h, uint8_t *buf, int size)
169
{
170
    RTPContext *s = h->priv_data;
171
    struct sockaddr_in from;
172
    socklen_t from_len;
173
    int len, fd_max, n;
174
    fd_set rfds;
175
#if 0
176
    for(;;) {
177
        from_len = sizeof(from);
178
        len = recvfrom (s->rtp_fd, buf, size, 0,
179
                        (struct sockaddr *)&from, &from_len);
180
        if (len < 0) {
181
            if (errno == EAGAIN || errno == EINTR)
182
                continue;
183
            return AVERROR_IO;
184
        }
185
        break;
186
    }
187
#else
188
    for(;;) {
189
        /* build fdset to listen to RTP and RTCP packets */
190
        FD_ZERO(&rfds);
191
        fd_max = s->rtp_fd;
192
        FD_SET(s->rtp_fd, &rfds);
193
        if (s->rtcp_fd > fd_max)
194
            fd_max = s->rtcp_fd;
195
        FD_SET(s->rtcp_fd, &rfds);
196
        n = select(fd_max + 1, &rfds, NULL, NULL, NULL);
197
        if (n > 0) {
198
            /* first try RTCP */
199
            if (FD_ISSET(s->rtcp_fd, &rfds)) {
200
                from_len = sizeof(from);
201
                len = recvfrom (s->rtcp_fd, buf, size, 0,
202
                                (struct sockaddr *)&from, &from_len);
203
                if (len < 0) {
204
                    if (errno == EAGAIN || errno == EINTR)
205
                        continue;
206
                    return AVERROR_IO;
207
                }
208
                break;
209
            }
210
            /* then RTP */
211
            if (FD_ISSET(s->rtp_fd, &rfds)) {
212
                from_len = sizeof(from);
213
                len = recvfrom (s->rtp_fd, buf, size, 0,
214
                                (struct sockaddr *)&from, &from_len);
215
                if (len < 0) {
216
                    if (errno == EAGAIN || errno == EINTR)
217
                        continue;
218
                    return AVERROR_IO;
219
                }
220
                break;
221
            }
222
        }
223
    }
224
#endif
225
    return len;
226
}
227

    
228
static int rtp_write(URLContext *h, uint8_t *buf, int size)
229
{
230
    RTPContext *s = h->priv_data;
231
    int ret;
232
    URLContext *hd;
233

    
234
    if (buf[1] >= 200 && buf[1] <= 204) {
235
        /* RTCP payload type */
236
        hd = s->rtcp_hd;
237
    } else {
238
        /* RTP payload type */
239
        hd = s->rtp_hd;
240
    }
241

    
242
    ret = url_write(hd, buf, size);
243
#if 0
244
    {
245
        struct timespec ts;
246
        ts.tv_sec = 0;
247
        ts.tv_nsec = 10 * 1000000;
248
        nanosleep(&ts, NULL);
249
    }
250
#endif
251
    return ret;
252
}
253

    
254
static int rtp_close(URLContext *h)
255
{
256
    RTPContext *s = h->priv_data;
257

    
258
    url_close(s->rtp_hd);
259
    url_close(s->rtcp_hd);
260
    av_free(s);
261
    return 0;
262
}
263

    
264
/**
265
 * Return the local port used by the RTP connexion
266
 * @param s1 media file context
267
 * @return the local port number
268
 */
269
int rtp_get_local_port(URLContext *h)
270
{
271
    RTPContext *s = h->priv_data;
272
    return udp_get_local_port(s->rtp_hd);
273
}
274

    
275
/**
276
 * Return the rtp and rtcp file handles for select() usage to wait for several RTP
277
 * streams at the same time.
278
 * @param h media file context
279
 */
280
void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
281
{
282
    RTPContext *s = h->priv_data;
283

    
284
    *prtp_fd = s->rtp_fd;
285
    *prtcp_fd = s->rtcp_fd;
286
}
287

    
288
URLProtocol rtp_protocol = {
289
    "rtp",
290
    rtp_open,
291
    rtp_read,
292
    rtp_write,
293
    NULL, /* seek */
294
    rtp_close,
295
};