Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpproto.c @ 756fb7fe

History | View | Annotate | Download (7.88 KB)

1 3b50d2ad Fabrice Bellard
/*
2
 * RTP network protocol
3
 * Copyright (c) 2002 Fabrice Bellard.
4
 *
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
#include "avformat.h"
22
23
#include <unistd.h>
24 51885599 Fabrice Bellard
#include <stdarg.h>
25 42572ef5 Ramiro Polla
#include "network.h"
26 3b50d2ad Fabrice Bellard
#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 51885599 Fabrice Bellard
51 3b50d2ad Fabrice Bellard
    char buf[1024];
52
    char path[1024];
53 115329f1 Diego Biurrun
54
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
55 3b50d2ad Fabrice Bellard
              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 51885599 Fabrice Bellard
/* add option to url of the form:
67
   "http://host:port/path?option1=val1&option2=val2... */
68 5c91a675 Zdenek Kabelac
static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
69 51885599 Fabrice Bellard
{
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 5c91a675 Zdenek Kabelac
static void build_udp_url(char *buf, int buf_size,
84 bb270c08 Diego Biurrun
                          const char *hostname, int port,
85
                          int local_port, int multicast, int ttl)
86 51885599 Fabrice Bellard
{
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 642d4a1a Diego Pettenò
        url_add_option(buf, buf_size, "multicast=1");
92 51885599 Fabrice Bellard
    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 115329f1 Diego Biurrun
 * option: 'multicast=1' : enable multicast
99 51885599 Fabrice Bellard
 *         'ttl=n'       : set the ttl value (for multicast only)
100
 *         'localport=n' : set the local port to n
101
 *
102
 */
103 3b50d2ad Fabrice Bellard
static int rtp_open(URLContext *h, const char *uri, int flags)
104
{
105
    RTPContext *s;
106 51885599 Fabrice Bellard
    int port, is_output, is_multicast, ttl, local_port;
107 3b50d2ad Fabrice Bellard
    char hostname[256];
108
    char buf[1024];
109
    char path[1024];
110 51885599 Fabrice Bellard
    const char *p;
111 115329f1 Diego Biurrun
112 3b50d2ad Fabrice Bellard
    is_output = (flags & URL_WRONLY);
113
114
    s = av_mallocz(sizeof(RTPContext));
115
    if (!s)
116 8fa36ae0 François Revol
        return AVERROR(ENOMEM);
117 3b50d2ad Fabrice Bellard
    h->priv_data = s;
118 115329f1 Diego Biurrun
119
    url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
120 3b50d2ad Fabrice Bellard
              path, sizeof(path), uri);
121 51885599 Fabrice Bellard
    /* 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 3b50d2ad Fabrice Bellard
136 51885599 Fabrice Bellard
    build_udp_url(buf, sizeof(buf),
137
                  hostname, port, local_port, is_multicast, ttl);
138 3b50d2ad Fabrice Bellard
    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 115329f1 Diego Biurrun
145 51885599 Fabrice Bellard
    build_udp_url(buf, sizeof(buf),
146
                  hostname, port + 1, local_port + 1, is_multicast, ttl);
147 3b50d2ad Fabrice Bellard
    if (url_open(&s->rtcp_hd, buf, flags) < 0)
148
        goto fail;
149 115329f1 Diego Biurrun
150 3b50d2ad Fabrice Bellard
    /* 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 115329f1 Diego Biurrun
    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
156 3b50d2ad Fabrice Bellard
    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 0bd586c5 Mike Melanson
    return AVERROR_IO;
166 3b50d2ad Fabrice Bellard
}
167
168 0c1a9eda Zdenek Kabelac
static int rtp_read(URLContext *h, uint8_t *buf, int size)
169 3b50d2ad Fabrice Bellard
{
170
    RTPContext *s = h->priv_data;
171
    struct sockaddr_in from;
172 191e8ca7 Måns Rullgård
    socklen_t from_len;
173
    int len, fd_max, n;
174 3b50d2ad Fabrice Bellard
    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 0bd586c5 Mike Melanson
            return AVERROR_IO;
184 3b50d2ad Fabrice Bellard
        }
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 0bd586c5 Mike Melanson
                    return AVERROR_IO;
207 3b50d2ad Fabrice Bellard
                }
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 0bd586c5 Mike Melanson
                    return AVERROR_IO;
219 3b50d2ad Fabrice Bellard
                }
220
                break;
221
            }
222
        }
223
    }
224
#endif
225
    return len;
226
}
227
228 0c1a9eda Zdenek Kabelac
static int rtp_write(URLContext *h, uint8_t *buf, int size)
229 3b50d2ad Fabrice Bellard
{
230
    RTPContext *s = h->priv_data;
231 51885599 Fabrice Bellard
    int ret;
232 3b50d2ad Fabrice Bellard
    URLContext *hd;
233 115329f1 Diego Biurrun
234 3b50d2ad Fabrice Bellard
    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
};