Mercurial > libavformat.hg
annotate rtpproto.c @ 1206:e60bf67d9bf8 libavformat
The reader ignores the size of the ASF data object and keeps on
reading even beyond it.
Therefore if the ASF file includes an index object at its end, the
reader will treat the index like data, but of course will fail since
it thinks that the data is corrupted.
When reading an asf file with an index object, ffmpeg will
complain at the end of the file that it read an invalid header.
Patch by Kohn Emil Dan, < emild A cs P technion P ac P il >
Original thead:
Date: Apr 18, 2006 4:11 PM
Subject: [Ffmpeg-devel] Two ASF related bugs and fixes
author | gpoirier |
---|---|
date | Sat, 29 Jul 2006 16:07:19 +0000 |
parents | edbe5c3717f9 |
children | 7474cc6383d4 |
rev | line source |
---|---|
0 | 1 /* |
2 * RTP network protocol | |
3 * Copyright (c) 2002 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 */ |
19 #include "avformat.h" | |
20 | |
21 #include <unistd.h> | |
22 #include <stdarg.h> | |
23 #include <sys/types.h> | |
24 #include <sys/socket.h> | |
25 #include <netinet/in.h> | |
26 #ifndef __BEOS__ | |
27 # include <arpa/inet.h> | |
28 #else | |
29 # include "barpainet.h" | |
30 #endif | |
31 #include <netdb.h> | |
32 #include <fcntl.h> | |
33 | |
34 #define RTP_TX_BUF_SIZE (64 * 1024) | |
35 #define RTP_RX_BUF_SIZE (128 * 1024) | |
36 | |
37 typedef struct RTPContext { | |
38 URLContext *rtp_hd, *rtcp_hd; | |
39 int rtp_fd, rtcp_fd; | |
40 } RTPContext; | |
41 | |
42 /** | |
43 * If no filename is given to av_open_input_file because you want to | |
44 * get the local port first, then you must call this function to set | |
45 * the remote server address. | |
46 * | |
47 * @param s1 media file context | |
48 * @param uri of the remote server | |
49 * @return zero if no error. | |
50 */ | |
51 int rtp_set_remote_url(URLContext *h, const char *uri) | |
52 { | |
53 RTPContext *s = h->priv_data; | |
54 char hostname[256]; | |
55 int port; | |
56 | |
57 char buf[1024]; | |
58 char path[1024]; | |
885 | 59 |
60 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 61 path, sizeof(path), uri); |
62 | |
63 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); | |
64 udp_set_remote_url(s->rtp_hd, buf); | |
65 | |
66 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path); | |
67 udp_set_remote_url(s->rtcp_hd, buf); | |
68 return 0; | |
69 } | |
70 | |
71 | |
72 /* add option to url of the form: | |
73 "http://host:port/path?option1=val1&option2=val2... */ | |
64 | 74 static void url_add_option(char *buf, int buf_size, const char *fmt, ...) |
0 | 75 { |
76 char buf1[1024]; | |
77 va_list ap; | |
78 | |
79 va_start(ap, fmt); | |
80 if (strchr(buf, '?')) | |
81 pstrcat(buf, buf_size, "&"); | |
82 else | |
83 pstrcat(buf, buf_size, "?"); | |
84 vsnprintf(buf1, sizeof(buf1), fmt, ap); | |
85 pstrcat(buf, buf_size, buf1); | |
86 va_end(ap); | |
87 } | |
88 | |
64 | 89 static void build_udp_url(char *buf, int buf_size, |
887 | 90 const char *hostname, int port, |
91 int local_port, int multicast, int ttl) | |
0 | 92 { |
93 snprintf(buf, buf_size, "udp://%s:%d", hostname, port); | |
94 if (local_port >= 0) | |
95 url_add_option(buf, buf_size, "localport=%d", local_port); | |
96 if (multicast) | |
97 url_add_option(buf, buf_size, "multicast=1", multicast); | |
98 if (ttl >= 0) | |
99 url_add_option(buf, buf_size, "ttl=%d", ttl); | |
100 } | |
101 | |
102 /* | |
103 * url syntax: rtp://host:port[?option=val...] | |
885 | 104 * option: 'multicast=1' : enable multicast |
0 | 105 * 'ttl=n' : set the ttl value (for multicast only) |
106 * 'localport=n' : set the local port to n | |
107 * | |
108 */ | |
109 static int rtp_open(URLContext *h, const char *uri, int flags) | |
110 { | |
111 RTPContext *s; | |
112 int port, is_output, is_multicast, ttl, local_port; | |
113 char hostname[256]; | |
114 char buf[1024]; | |
115 char path[1024]; | |
116 const char *p; | |
885 | 117 |
0 | 118 is_output = (flags & URL_WRONLY); |
119 | |
120 s = av_mallocz(sizeof(RTPContext)); | |
121 if (!s) | |
122 return -ENOMEM; | |
123 h->priv_data = s; | |
885 | 124 |
125 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 126 path, sizeof(path), uri); |
127 /* extract parameters */ | |
128 is_multicast = 0; | |
129 ttl = -1; | |
130 local_port = -1; | |
131 p = strchr(uri, '?'); | |
132 if (p) { | |
133 is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); | |
134 if (find_info_tag(buf, sizeof(buf), "ttl", p)) { | |
135 ttl = strtol(buf, NULL, 10); | |
136 } | |
137 if (find_info_tag(buf, sizeof(buf), "localport", p)) { | |
138 local_port = strtol(buf, NULL, 10); | |
139 } | |
140 } | |
141 | |
142 build_udp_url(buf, sizeof(buf), | |
143 hostname, port, local_port, is_multicast, ttl); | |
144 if (url_open(&s->rtp_hd, buf, flags) < 0) | |
145 goto fail; | |
146 local_port = udp_get_local_port(s->rtp_hd); | |
147 /* XXX: need to open another connexion if the port is not even */ | |
148 | |
149 /* well, should suppress localport in path */ | |
885 | 150 |
0 | 151 build_udp_url(buf, sizeof(buf), |
152 hostname, port + 1, local_port + 1, is_multicast, ttl); | |
153 if (url_open(&s->rtcp_hd, buf, flags) < 0) | |
154 goto fail; | |
885 | 155 |
0 | 156 /* just to ease handle access. XXX: need to suppress direct handle |
157 access */ | |
158 s->rtp_fd = udp_get_file_handle(s->rtp_hd); | |
159 s->rtcp_fd = udp_get_file_handle(s->rtcp_hd); | |
160 | |
885 | 161 h->max_packet_size = url_get_max_packet_size(s->rtp_hd); |
0 | 162 h->is_streamed = 1; |
163 return 0; | |
164 | |
165 fail: | |
166 if (s->rtp_hd) | |
167 url_close(s->rtp_hd); | |
168 if (s->rtcp_hd) | |
169 url_close(s->rtcp_hd); | |
170 av_free(s); | |
482 | 171 return AVERROR_IO; |
0 | 172 } |
173 | |
65 | 174 static int rtp_read(URLContext *h, uint8_t *buf, int size) |
0 | 175 { |
176 RTPContext *s = h->priv_data; | |
177 struct sockaddr_in from; | |
178 int from_len, len, fd_max, n; | |
179 fd_set rfds; | |
180 #if 0 | |
181 for(;;) { | |
182 from_len = sizeof(from); | |
183 len = recvfrom (s->rtp_fd, buf, size, 0, | |
184 (struct sockaddr *)&from, &from_len); | |
185 if (len < 0) { | |
186 if (errno == EAGAIN || errno == EINTR) | |
187 continue; | |
482 | 188 return AVERROR_IO; |
0 | 189 } |
190 break; | |
191 } | |
192 #else | |
193 for(;;) { | |
194 /* build fdset to listen to RTP and RTCP packets */ | |
195 FD_ZERO(&rfds); | |
196 fd_max = s->rtp_fd; | |
197 FD_SET(s->rtp_fd, &rfds); | |
198 if (s->rtcp_fd > fd_max) | |
199 fd_max = s->rtcp_fd; | |
200 FD_SET(s->rtcp_fd, &rfds); | |
201 n = select(fd_max + 1, &rfds, NULL, NULL, NULL); | |
202 if (n > 0) { | |
203 /* first try RTCP */ | |
204 if (FD_ISSET(s->rtcp_fd, &rfds)) { | |
205 from_len = sizeof(from); | |
206 len = recvfrom (s->rtcp_fd, buf, size, 0, | |
207 (struct sockaddr *)&from, &from_len); | |
208 if (len < 0) { | |
209 if (errno == EAGAIN || errno == EINTR) | |
210 continue; | |
482 | 211 return AVERROR_IO; |
0 | 212 } |
213 break; | |
214 } | |
215 /* then RTP */ | |
216 if (FD_ISSET(s->rtp_fd, &rfds)) { | |
217 from_len = sizeof(from); | |
218 len = recvfrom (s->rtp_fd, buf, size, 0, | |
219 (struct sockaddr *)&from, &from_len); | |
220 if (len < 0) { | |
221 if (errno == EAGAIN || errno == EINTR) | |
222 continue; | |
482 | 223 return AVERROR_IO; |
0 | 224 } |
225 break; | |
226 } | |
227 } | |
228 } | |
229 #endif | |
230 return len; | |
231 } | |
232 | |
65 | 233 static int rtp_write(URLContext *h, uint8_t *buf, int size) |
0 | 234 { |
235 RTPContext *s = h->priv_data; | |
236 int ret; | |
237 URLContext *hd; | |
885 | 238 |
0 | 239 if (buf[1] >= 200 && buf[1] <= 204) { |
240 /* RTCP payload type */ | |
241 hd = s->rtcp_hd; | |
242 } else { | |
243 /* RTP payload type */ | |
244 hd = s->rtp_hd; | |
245 } | |
246 | |
247 ret = url_write(hd, buf, size); | |
248 #if 0 | |
249 { | |
250 struct timespec ts; | |
251 ts.tv_sec = 0; | |
252 ts.tv_nsec = 10 * 1000000; | |
253 nanosleep(&ts, NULL); | |
254 } | |
255 #endif | |
256 return ret; | |
257 } | |
258 | |
259 static int rtp_close(URLContext *h) | |
260 { | |
261 RTPContext *s = h->priv_data; | |
262 | |
263 url_close(s->rtp_hd); | |
264 url_close(s->rtcp_hd); | |
265 av_free(s); | |
266 return 0; | |
267 } | |
268 | |
269 /** | |
270 * Return the local port used by the RTP connexion | |
271 * @param s1 media file context | |
272 * @return the local port number | |
273 */ | |
274 int rtp_get_local_port(URLContext *h) | |
275 { | |
276 RTPContext *s = h->priv_data; | |
277 return udp_get_local_port(s->rtp_hd); | |
278 } | |
279 | |
280 /** | |
281 * Return the rtp and rtcp file handles for select() usage to wait for several RTP | |
282 * streams at the same time. | |
283 * @param h media file context | |
284 */ | |
285 void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd) | |
286 { | |
287 RTPContext *s = h->priv_data; | |
288 | |
289 *prtp_fd = s->rtp_fd; | |
290 *prtcp_fd = s->rtcp_fd; | |
291 } | |
292 | |
293 URLProtocol rtp_protocol = { | |
294 "rtp", | |
295 rtp_open, | |
296 rtp_read, | |
297 rtp_write, | |
298 NULL, /* seek */ | |
299 rtp_close, | |
300 }; |