bump micro version: new string functions
[libav.git] / libavformat / rtpproto.c
CommitLineData
3b50d2ad
FB
1/*
2 * RTP network protocol
3 * Copyright (c) 2002 Fabrice Bellard.
4 *
b78e7197
DB
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
3b50d2ad
FB
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
b78e7197 10 * version 2.1 of the License, or (at your option) any later version.
3b50d2ad 11 *
b78e7197 12 * FFmpeg is distributed in the hope that it will be useful,
3b50d2ad
FB
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
b78e7197 18 * License along with FFmpeg; if not, write to the Free Software
5509bffa 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3b50d2ad
FB
20 */
21#include "avformat.h"
22
23#include <unistd.h>
51885599 24#include <stdarg.h>
42572ef5 25#include "network.h"
3b50d2ad
FB
26#include <fcntl.h>
27
28#define RTP_TX_BUF_SIZE (64 * 1024)
29#define RTP_RX_BUF_SIZE (128 * 1024)
30
31typedef 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 *
3b50d2ad
FB
41 * @param s1 media file context
42 * @param uri of the remote server
43 * @return zero if no error.
44 */
45int rtp_set_remote_url(URLContext *h, const char *uri)
46{
47 RTPContext *s = h->priv_data;
48 char hostname[256];
49 int port;
51885599 50
3b50d2ad
FB
51 char buf[1024];
52 char path[1024];
115329f1
DB
53
54 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
3b50d2ad
FB
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
51885599
FB
66/* add option to url of the form:
67 "http://host:port/path?option1=val1&option2=val2... */
5c91a675 68static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
51885599
FB
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
5c91a675 83static void build_udp_url(char *buf, int buf_size,
bb270c08
DB
84 const char *hostname, int port,
85 int local_port, int multicast, int ttl)
51885599
FB
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)
642d4a1a 91 url_add_option(buf, buf_size, "multicast=1");
51885599
FB
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...]
115329f1 98 * option: 'multicast=1' : enable multicast
51885599
FB
99 * 'ttl=n' : set the ttl value (for multicast only)
100 * 'localport=n' : set the local port to n
101 *
102 */
3b50d2ad
FB
103static int rtp_open(URLContext *h, const char *uri, int flags)
104{
105 RTPContext *s;
51885599 106 int port, is_output, is_multicast, ttl, local_port;
3b50d2ad
FB
107 char hostname[256];
108 char buf[1024];
109 char path[1024];
51885599 110 const char *p;
115329f1 111
3b50d2ad
FB
112 is_output = (flags & URL_WRONLY);
113
114 s = av_mallocz(sizeof(RTPContext));
115 if (!s)
8fa36ae0 116 return AVERROR(ENOMEM);
3b50d2ad 117 h->priv_data = s;
115329f1
DB
118
119 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
3b50d2ad 120 path, sizeof(path), uri);
51885599
FB
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 }
3b50d2ad 135
51885599
FB
136 build_udp_url(buf, sizeof(buf),
137 hostname, port, local_port, is_multicast, ttl);
3b50d2ad
FB
138 if (url_open(&s->rtp_hd, buf, flags) < 0)
139 goto fail;
140 local_port = udp_get_local_port(s->rtp_hd);
b484ec78 141 /* XXX: need to open another connection if the port is not even */
3b50d2ad
FB
142
143 /* well, should suppress localport in path */
115329f1 144
51885599
FB
145 build_udp_url(buf, sizeof(buf),
146 hostname, port + 1, local_port + 1, is_multicast, ttl);
3b50d2ad
FB
147 if (url_open(&s->rtcp_hd, buf, flags) < 0)
148 goto fail;
115329f1 149
3b50d2ad
FB
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
115329f1 155 h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
3b50d2ad
FB
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);
0bd586c5 165 return AVERROR_IO;
3b50d2ad
FB
166}
167
0c1a9eda 168static int rtp_read(URLContext *h, uint8_t *buf, int size)
3b50d2ad
FB
169{
170 RTPContext *s = h->priv_data;
171 struct sockaddr_in from;
191e8ca7
MR
172 socklen_t from_len;
173 int len, fd_max, n;
3b50d2ad
FB
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) {
8da4034f
AB
181 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
182 ff_neterrno() == FF_NETERROR(EINTR))
3b50d2ad 183 continue;
0bd586c5 184 return AVERROR_IO;
3b50d2ad
FB
185 }
186 break;
187 }
188#else
189 for(;;) {
190 /* build fdset to listen to RTP and RTCP packets */
191 FD_ZERO(&rfds);
192 fd_max = s->rtp_fd;
193 FD_SET(s->rtp_fd, &rfds);
194 if (s->rtcp_fd > fd_max)
195 fd_max = s->rtcp_fd;
196 FD_SET(s->rtcp_fd, &rfds);
197 n = select(fd_max + 1, &rfds, NULL, NULL, NULL);
198 if (n > 0) {
199 /* first try RTCP */
200 if (FD_ISSET(s->rtcp_fd, &rfds)) {
201 from_len = sizeof(from);
202 len = recvfrom (s->rtcp_fd, buf, size, 0,
203 (struct sockaddr *)&from, &from_len);
204 if (len < 0) {
8da4034f
AB
205 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
206 ff_neterrno() == FF_NETERROR(EINTR))
3b50d2ad 207 continue;
0bd586c5 208 return AVERROR_IO;
3b50d2ad
FB
209 }
210 break;
211 }
212 /* then RTP */
213 if (FD_ISSET(s->rtp_fd, &rfds)) {
214 from_len = sizeof(from);
215 len = recvfrom (s->rtp_fd, buf, size, 0,
216 (struct sockaddr *)&from, &from_len);
217 if (len < 0) {
8da4034f
AB
218 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
219 ff_neterrno() == FF_NETERROR(EINTR))
3b50d2ad 220 continue;
0bd586c5 221 return AVERROR_IO;
3b50d2ad
FB
222 }
223 break;
224 }
225 }
226 }
227#endif
228 return len;
229}
230
0c1a9eda 231static int rtp_write(URLContext *h, uint8_t *buf, int size)
3b50d2ad
FB
232{
233 RTPContext *s = h->priv_data;
51885599 234 int ret;
3b50d2ad 235 URLContext *hd;
115329f1 236
3b50d2ad
FB
237 if (buf[1] >= 200 && buf[1] <= 204) {
238 /* RTCP payload type */
239 hd = s->rtcp_hd;
240 } else {
241 /* RTP payload type */
242 hd = s->rtp_hd;
243 }
244
245 ret = url_write(hd, buf, size);
246#if 0
247 {
248 struct timespec ts;
249 ts.tv_sec = 0;
250 ts.tv_nsec = 10 * 1000000;
251 nanosleep(&ts, NULL);
252 }
253#endif
254 return ret;
255}
256
257static int rtp_close(URLContext *h)
258{
259 RTPContext *s = h->priv_data;
260
261 url_close(s->rtp_hd);
262 url_close(s->rtcp_hd);
263 av_free(s);
264 return 0;
265}
266
267/**
b484ec78 268 * Return the local port used by the RTP connection
3b50d2ad
FB
269 * @param s1 media file context
270 * @return the local port number
271 */
272int rtp_get_local_port(URLContext *h)
273{
274 RTPContext *s = h->priv_data;
275 return udp_get_local_port(s->rtp_hd);
276}
277
278/**
279 * Return the rtp and rtcp file handles for select() usage to wait for several RTP
280 * streams at the same time.
281 * @param h media file context
282 */
283void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
284{
285 RTPContext *s = h->priv_data;
286
287 *prtp_fd = s->rtp_fd;
288 *prtcp_fd = s->rtcp_fd;
289}
290
291URLProtocol rtp_protocol = {
292 "rtp",
293 rtp_open,
294 rtp_read,
295 rtp_write,
296 NULL, /* seek */
297 rtp_close,
298};