Mercurial > libavformat.hg
annotate rtpproto.c @ 4387:5c42816e12c6 libavformat
Add "AVFormatContext *ctx" (that being the RTSP demuxer's) as first argument
to the parse_packet() function pointer in RTPDynamicProtocolHandlers. This
allows these functions to peek back and retrieve values from the demuxer's
context (or RTSPState). The ASF/RTP payload parser will use this to be able
to parse SDP values (which occur even before the payload ID is given), store
them in the RTSPState and then retrieve them while parsing payload data. See
"[PATCH] RTSP-MS 13/15: add RTSP demuxer AVFormatContext to parse_packet()
function pointer (was: transport context)" mailinglist thread.
author | rbultje |
---|---|
date | Fri, 06 Feb 2009 01:37:19 +0000 |
parents | 49c1d3b27727 |
children | b34d9614b887 |
rev | line source |
---|---|
0 | 1 /* |
2 * RTP network protocol | |
4251
77e0c7511d41
cosmetics: Remove pointless period after copyright statement non-sentences.
diego
parents:
4206
diff
changeset
|
3 * Copyright (c) 2002 Fabrice Bellard |
0 | 4 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
0 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
0 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
0 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1332
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 20 */ |
3229 | 21 |
22 /** | |
4331
49c1d3b27727
Use full internal pathname in doxygen @file directives.
diego
parents:
4251
diff
changeset
|
23 * @file libavformat/rtpproto.c |
3229 | 24 * RTP protocol |
25 */ | |
26 | |
3286 | 27 #include "libavutil/avstring.h" |
0 | 28 #include "avformat.h" |
29 | |
30 #include <unistd.h> | |
31 #include <stdarg.h> | |
1754 | 32 #include "network.h" |
2782
419e121ce80a
Add #include "os_support.h" to restore OS/2 support.
diego
parents:
2274
diff
changeset
|
33 #include "os_support.h" |
0 | 34 #include <fcntl.h> |
4206 | 35 #if HAVE_SYS_SELECT_H |
3712
30d4d95e068f
Add needed include, make it compile without -D_BSD_SOURCE.
michael
parents:
3286
diff
changeset
|
36 #include <sys/select.h> |
3720
1968303c7566
Surround '#include <sys/select>' by HAVE_SYS_SELECT_H.
diego
parents:
3712
diff
changeset
|
37 #endif |
0 | 38 |
39 #define RTP_TX_BUF_SIZE (64 * 1024) | |
40 #define RTP_RX_BUF_SIZE (128 * 1024) | |
41 | |
42 typedef struct RTPContext { | |
43 URLContext *rtp_hd, *rtcp_hd; | |
44 int rtp_fd, rtcp_fd; | |
45 } RTPContext; | |
46 | |
47 /** | |
48 * If no filename is given to av_open_input_file because you want to | |
49 * get the local port first, then you must call this function to set | |
50 * the remote server address. | |
51 * | |
52 * @param s1 media file context | |
53 * @param uri of the remote server | |
54 * @return zero if no error. | |
55 */ | |
3229 | 56 |
0 | 57 int rtp_set_remote_url(URLContext *h, const char *uri) |
58 { | |
59 RTPContext *s = h->priv_data; | |
60 char hostname[256]; | |
61 int port; | |
62 | |
63 char buf[1024]; | |
64 char path[1024]; | |
885 | 65 |
66 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 67 path, sizeof(path), uri); |
68 | |
69 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); | |
70 udp_set_remote_url(s->rtp_hd, buf); | |
71 | |
72 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path); | |
73 udp_set_remote_url(s->rtcp_hd, buf); | |
74 return 0; | |
75 } | |
76 | |
77 | |
3229 | 78 /** |
79 * add option to url of the form: | |
80 * "http://host:port/path?option1=val1&option2=val2... | |
81 */ | |
82 | |
64 | 83 static void url_add_option(char *buf, int buf_size, const char *fmt, ...) |
0 | 84 { |
85 char buf1[1024]; | |
86 va_list ap; | |
87 | |
88 va_start(ap, fmt); | |
89 if (strchr(buf, '?')) | |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
90 av_strlcat(buf, "&", buf_size); |
0 | 91 else |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
92 av_strlcat(buf, "?", buf_size); |
0 | 93 vsnprintf(buf1, sizeof(buf1), fmt, ap); |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
94 av_strlcat(buf, buf1, buf_size); |
0 | 95 va_end(ap); |
96 } | |
97 | |
64 | 98 static void build_udp_url(char *buf, int buf_size, |
887 | 99 const char *hostname, int port, |
3228 | 100 int local_port, int ttl, |
101 int max_packet_size) | |
0 | 102 { |
103 snprintf(buf, buf_size, "udp://%s:%d", hostname, port); | |
104 if (local_port >= 0) | |
105 url_add_option(buf, buf_size, "localport=%d", local_port); | |
106 if (ttl >= 0) | |
107 url_add_option(buf, buf_size, "ttl=%d", ttl); | |
3228 | 108 if (max_packet_size >=0) |
109 url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size); | |
0 | 110 } |
111 | |
3229 | 112 /** |
0 | 113 * url syntax: rtp://host:port[?option=val...] |
3221 | 114 * option: 'ttl=n' : set the ttl value (for multicast only) |
0 | 115 * 'localport=n' : set the local port to n |
3228 | 116 * 'pkt_size=n' : set max packet size |
0 | 117 * |
118 */ | |
3229 | 119 |
0 | 120 static int rtp_open(URLContext *h, const char *uri, int flags) |
121 { | |
122 RTPContext *s; | |
3228 | 123 int port, is_output, ttl, local_port, max_packet_size; |
0 | 124 char hostname[256]; |
125 char buf[1024]; | |
126 char path[1024]; | |
127 const char *p; | |
885 | 128 |
0 | 129 is_output = (flags & URL_WRONLY); |
130 | |
131 s = av_mallocz(sizeof(RTPContext)); | |
132 if (!s) | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1754
diff
changeset
|
133 return AVERROR(ENOMEM); |
0 | 134 h->priv_data = s; |
885 | 135 |
136 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 137 path, sizeof(path), uri); |
138 /* extract parameters */ | |
139 ttl = -1; | |
140 local_port = -1; | |
3228 | 141 max_packet_size = -1; |
142 | |
0 | 143 p = strchr(uri, '?'); |
144 if (p) { | |
145 if (find_info_tag(buf, sizeof(buf), "ttl", p)) { | |
146 ttl = strtol(buf, NULL, 10); | |
147 } | |
148 if (find_info_tag(buf, sizeof(buf), "localport", p)) { | |
149 local_port = strtol(buf, NULL, 10); | |
150 } | |
3228 | 151 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { |
152 max_packet_size = strtol(buf, NULL, 10); | |
153 } | |
0 | 154 } |
155 | |
156 build_udp_url(buf, sizeof(buf), | |
3228 | 157 hostname, port, local_port, ttl, max_packet_size); |
0 | 158 if (url_open(&s->rtp_hd, buf, flags) < 0) |
159 goto fail; | |
160 local_port = udp_get_local_port(s->rtp_hd); | |
2079 | 161 /* XXX: need to open another connection if the port is not even */ |
0 | 162 |
163 /* well, should suppress localport in path */ | |
885 | 164 |
0 | 165 build_udp_url(buf, sizeof(buf), |
3228 | 166 hostname, port + 1, local_port + 1, ttl, max_packet_size); |
0 | 167 if (url_open(&s->rtcp_hd, buf, flags) < 0) |
168 goto fail; | |
885 | 169 |
0 | 170 /* just to ease handle access. XXX: need to suppress direct handle |
171 access */ | |
172 s->rtp_fd = udp_get_file_handle(s->rtp_hd); | |
173 s->rtcp_fd = udp_get_file_handle(s->rtcp_hd); | |
174 | |
885 | 175 h->max_packet_size = url_get_max_packet_size(s->rtp_hd); |
0 | 176 h->is_streamed = 1; |
177 return 0; | |
178 | |
179 fail: | |
180 if (s->rtp_hd) | |
181 url_close(s->rtp_hd); | |
182 if (s->rtcp_hd) | |
183 url_close(s->rtcp_hd); | |
184 av_free(s); | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
185 return AVERROR(EIO); |
0 | 186 } |
187 | |
65 | 188 static int rtp_read(URLContext *h, uint8_t *buf, int size) |
0 | 189 { |
190 RTPContext *s = h->priv_data; | |
191 struct sockaddr_in from; | |
1332 | 192 socklen_t from_len; |
193 int len, fd_max, n; | |
0 | 194 fd_set rfds; |
195 #if 0 | |
196 for(;;) { | |
197 from_len = sizeof(from); | |
198 len = recvfrom (s->rtp_fd, buf, size, 0, | |
199 (struct sockaddr *)&from, &from_len); | |
200 if (len < 0) { | |
2056
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
201 if (ff_neterrno() == FF_NETERROR(EAGAIN) || |
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
202 ff_neterrno() == FF_NETERROR(EINTR)) |
0 | 203 continue; |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
204 return AVERROR(EIO); |
0 | 205 } |
206 break; | |
207 } | |
208 #else | |
209 for(;;) { | |
210 /* build fdset to listen to RTP and RTCP packets */ | |
211 FD_ZERO(&rfds); | |
212 fd_max = s->rtp_fd; | |
213 FD_SET(s->rtp_fd, &rfds); | |
214 if (s->rtcp_fd > fd_max) | |
215 fd_max = s->rtcp_fd; | |
216 FD_SET(s->rtcp_fd, &rfds); | |
217 n = select(fd_max + 1, &rfds, NULL, NULL, NULL); | |
218 if (n > 0) { | |
219 /* first try RTCP */ | |
220 if (FD_ISSET(s->rtcp_fd, &rfds)) { | |
221 from_len = sizeof(from); | |
222 len = recvfrom (s->rtcp_fd, buf, size, 0, | |
223 (struct sockaddr *)&from, &from_len); | |
224 if (len < 0) { | |
2056
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
225 if (ff_neterrno() == FF_NETERROR(EAGAIN) || |
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
226 ff_neterrno() == FF_NETERROR(EINTR)) |
0 | 227 continue; |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
228 return AVERROR(EIO); |
0 | 229 } |
230 break; | |
231 } | |
232 /* then RTP */ | |
233 if (FD_ISSET(s->rtp_fd, &rfds)) { | |
234 from_len = sizeof(from); | |
235 len = recvfrom (s->rtp_fd, buf, size, 0, | |
236 (struct sockaddr *)&from, &from_len); | |
237 if (len < 0) { | |
2056
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
238 if (ff_neterrno() == FF_NETERROR(EAGAIN) || |
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
239 ff_neterrno() == FF_NETERROR(EINTR)) |
0 | 240 continue; |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
241 return AVERROR(EIO); |
0 | 242 } |
243 break; | |
244 } | |
245 } | |
246 } | |
247 #endif | |
248 return len; | |
249 } | |
250 | |
65 | 251 static int rtp_write(URLContext *h, uint8_t *buf, int size) |
0 | 252 { |
253 RTPContext *s = h->priv_data; | |
254 int ret; | |
255 URLContext *hd; | |
885 | 256 |
0 | 257 if (buf[1] >= 200 && buf[1] <= 204) { |
258 /* RTCP payload type */ | |
259 hd = s->rtcp_hd; | |
260 } else { | |
261 /* RTP payload type */ | |
262 hd = s->rtp_hd; | |
263 } | |
264 | |
265 ret = url_write(hd, buf, size); | |
266 #if 0 | |
267 { | |
268 struct timespec ts; | |
269 ts.tv_sec = 0; | |
270 ts.tv_nsec = 10 * 1000000; | |
271 nanosleep(&ts, NULL); | |
272 } | |
273 #endif | |
274 return ret; | |
275 } | |
276 | |
277 static int rtp_close(URLContext *h) | |
278 { | |
279 RTPContext *s = h->priv_data; | |
280 | |
281 url_close(s->rtp_hd); | |
282 url_close(s->rtcp_hd); | |
283 av_free(s); | |
284 return 0; | |
285 } | |
286 | |
287 /** | |
2079 | 288 * Return the local port used by the RTP connection |
0 | 289 * @param s1 media file context |
290 * @return the local port number | |
291 */ | |
3229 | 292 |
0 | 293 int rtp_get_local_port(URLContext *h) |
294 { | |
295 RTPContext *s = h->priv_data; | |
296 return udp_get_local_port(s->rtp_hd); | |
297 } | |
298 | |
299 /** | |
3229 | 300 * Return the rtp and rtcp file handles for select() usage to wait for |
301 * several RTP streams at the same time. | |
0 | 302 * @param h media file context |
303 */ | |
3229 | 304 |
0 | 305 void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd) |
306 { | |
307 RTPContext *s = h->priv_data; | |
308 | |
309 *prtp_fd = s->rtp_fd; | |
310 *prtcp_fd = s->rtcp_fd; | |
311 } | |
312 | |
313 URLProtocol rtp_protocol = { | |
314 "rtp", | |
315 rtp_open, | |
316 rtp_read, | |
317 rtp_write, | |
318 NULL, /* seek */ | |
319 rtp_close, | |
320 }; |