Mercurial > libavformat.hg
annotate rtpproto.c @ 1960:c0289552590f libavformat
Change the vhook code to send real timestamps to the filters instead of the
current time of day, which is useless, and which the filters could just as
easily query for themselves.
patch by Bobby Bingham, uhmmmm gmail com
author | diego |
---|---|
date | Thu, 29 Mar 2007 05:24:35 +0000 |
parents | f67a8d12053d |
children | eeea52739ff3 |
rev | line source |
---|---|
0 | 1 /* |
2 * RTP network protocol | |
3 * Copyright (c) 2002 Fabrice Bellard. | |
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 */ |
21 #include "avformat.h" | |
22 | |
23 #include <unistd.h> | |
24 #include <stdarg.h> | |
1754 | 25 #include "network.h" |
0 | 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]; | |
885 | 53 |
54 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 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... */ | |
64 | 68 static void url_add_option(char *buf, int buf_size, const char *fmt, ...) |
0 | 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 | |
64 | 83 static void build_udp_url(char *buf, int buf_size, |
887 | 84 const char *hostname, int port, |
85 int local_port, int multicast, int ttl) | |
0 | 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) | |
1930 | 91 url_add_option(buf, buf_size, "multicast=1"); |
0 | 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...] | |
885 | 98 * option: 'multicast=1' : enable multicast |
0 | 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; | |
885 | 111 |
0 | 112 is_output = (flags & URL_WRONLY); |
113 | |
114 s = av_mallocz(sizeof(RTPContext)); | |
115 if (!s) | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1754
diff
changeset
|
116 return AVERROR(ENOMEM); |
0 | 117 h->priv_data = s; |
885 | 118 |
119 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 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 */ | |
885 | 144 |
0 | 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; | |
885 | 149 |
0 | 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 | |
885 | 155 h->max_packet_size = url_get_max_packet_size(s->rtp_hd); |
0 | 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); | |
482 | 165 return AVERROR_IO; |
0 | 166 } |
167 | |
65 | 168 static int rtp_read(URLContext *h, uint8_t *buf, int size) |
0 | 169 { |
170 RTPContext *s = h->priv_data; | |
171 struct sockaddr_in from; | |
1332 | 172 socklen_t from_len; |
173 int len, fd_max, n; | |
0 | 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; | |
482 | 183 return AVERROR_IO; |
0 | 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; | |
482 | 206 return AVERROR_IO; |
0 | 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; | |
482 | 218 return AVERROR_IO; |
0 | 219 } |
220 break; | |
221 } | |
222 } | |
223 } | |
224 #endif | |
225 return len; | |
226 } | |
227 | |
65 | 228 static int rtp_write(URLContext *h, uint8_t *buf, int size) |
0 | 229 { |
230 RTPContext *s = h->priv_data; | |
231 int ret; | |
232 URLContext *hd; | |
885 | 233 |
0 | 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 }; |