Mercurial > libavformat.hg
annotate rtpproto.c @ 3068:9cc9ff5aff9c libavformat
set bps to uncompressed original sound data for compressed audio
according to aiff specs, qt set it to 16 for mace and ima4,
fail if block align is not set.
author | bcoudurier |
---|---|
date | Mon, 25 Feb 2008 12:00:31 +0000 |
parents | 419e121ce80a |
children | e17b25e8a34e |
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" | |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
22 #include "avstring.h" |
0 | 23 |
24 #include <unistd.h> | |
25 #include <stdarg.h> | |
1754 | 26 #include "network.h" |
2782
419e121ce80a
Add #include "os_support.h" to restore OS/2 support.
diego
parents:
2274
diff
changeset
|
27 #include "os_support.h" |
0 | 28 #include <fcntl.h> |
29 | |
30 #define RTP_TX_BUF_SIZE (64 * 1024) | |
31 #define RTP_RX_BUF_SIZE (128 * 1024) | |
32 | |
33 typedef struct RTPContext { | |
34 URLContext *rtp_hd, *rtcp_hd; | |
35 int rtp_fd, rtcp_fd; | |
36 } RTPContext; | |
37 | |
38 /** | |
39 * If no filename is given to av_open_input_file because you want to | |
40 * get the local port first, then you must call this function to set | |
41 * the remote server address. | |
42 * | |
43 * @param s1 media file context | |
44 * @param uri of the remote server | |
45 * @return zero if no error. | |
46 */ | |
47 int rtp_set_remote_url(URLContext *h, const char *uri) | |
48 { | |
49 RTPContext *s = h->priv_data; | |
50 char hostname[256]; | |
51 int port; | |
52 | |
53 char buf[1024]; | |
54 char path[1024]; | |
885 | 55 |
56 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 57 path, sizeof(path), uri); |
58 | |
59 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); | |
60 udp_set_remote_url(s->rtp_hd, buf); | |
61 | |
62 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path); | |
63 udp_set_remote_url(s->rtcp_hd, buf); | |
64 return 0; | |
65 } | |
66 | |
67 | |
68 /* add option to url of the form: | |
69 "http://host:port/path?option1=val1&option2=val2... */ | |
64 | 70 static void url_add_option(char *buf, int buf_size, const char *fmt, ...) |
0 | 71 { |
72 char buf1[1024]; | |
73 va_list ap; | |
74 | |
75 va_start(ap, fmt); | |
76 if (strchr(buf, '?')) | |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
77 av_strlcat(buf, "&", buf_size); |
0 | 78 else |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
79 av_strlcat(buf, "?", buf_size); |
0 | 80 vsnprintf(buf1, sizeof(buf1), fmt, ap); |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2079
diff
changeset
|
81 av_strlcat(buf, buf1, buf_size); |
0 | 82 va_end(ap); |
83 } | |
84 | |
64 | 85 static void build_udp_url(char *buf, int buf_size, |
887 | 86 const char *hostname, int port, |
87 int local_port, int multicast, int ttl) | |
0 | 88 { |
89 snprintf(buf, buf_size, "udp://%s:%d", hostname, port); | |
90 if (local_port >= 0) | |
91 url_add_option(buf, buf_size, "localport=%d", local_port); | |
92 if (multicast) | |
1930 | 93 url_add_option(buf, buf_size, "multicast=1"); |
0 | 94 if (ttl >= 0) |
95 url_add_option(buf, buf_size, "ttl=%d", ttl); | |
96 } | |
97 | |
98 /* | |
99 * url syntax: rtp://host:port[?option=val...] | |
885 | 100 * option: 'multicast=1' : enable multicast |
0 | 101 * 'ttl=n' : set the ttl value (for multicast only) |
102 * 'localport=n' : set the local port to n | |
103 * | |
104 */ | |
105 static int rtp_open(URLContext *h, const char *uri, int flags) | |
106 { | |
107 RTPContext *s; | |
108 int port, is_output, is_multicast, ttl, local_port; | |
109 char hostname[256]; | |
110 char buf[1024]; | |
111 char path[1024]; | |
112 const char *p; | |
885 | 113 |
0 | 114 is_output = (flags & URL_WRONLY); |
115 | |
116 s = av_mallocz(sizeof(RTPContext)); | |
117 if (!s) | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1754
diff
changeset
|
118 return AVERROR(ENOMEM); |
0 | 119 h->priv_data = s; |
885 | 120 |
121 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, | |
0 | 122 path, sizeof(path), uri); |
123 /* extract parameters */ | |
124 is_multicast = 0; | |
125 ttl = -1; | |
126 local_port = -1; | |
127 p = strchr(uri, '?'); | |
128 if (p) { | |
129 is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); | |
130 if (find_info_tag(buf, sizeof(buf), "ttl", p)) { | |
131 ttl = strtol(buf, NULL, 10); | |
132 } | |
133 if (find_info_tag(buf, sizeof(buf), "localport", p)) { | |
134 local_port = strtol(buf, NULL, 10); | |
135 } | |
136 } | |
137 | |
138 build_udp_url(buf, sizeof(buf), | |
139 hostname, port, local_port, is_multicast, ttl); | |
140 if (url_open(&s->rtp_hd, buf, flags) < 0) | |
141 goto fail; | |
142 local_port = udp_get_local_port(s->rtp_hd); | |
2079 | 143 /* XXX: need to open another connection if the port is not even */ |
0 | 144 |
145 /* well, should suppress localport in path */ | |
885 | 146 |
0 | 147 build_udp_url(buf, sizeof(buf), |
148 hostname, port + 1, local_port + 1, is_multicast, ttl); | |
149 if (url_open(&s->rtcp_hd, buf, flags) < 0) | |
150 goto fail; | |
885 | 151 |
0 | 152 /* just to ease handle access. XXX: need to suppress direct handle |
153 access */ | |
154 s->rtp_fd = udp_get_file_handle(s->rtp_hd); | |
155 s->rtcp_fd = udp_get_file_handle(s->rtcp_hd); | |
156 | |
885 | 157 h->max_packet_size = url_get_max_packet_size(s->rtp_hd); |
0 | 158 h->is_streamed = 1; |
159 return 0; | |
160 | |
161 fail: | |
162 if (s->rtp_hd) | |
163 url_close(s->rtp_hd); | |
164 if (s->rtcp_hd) | |
165 url_close(s->rtcp_hd); | |
166 av_free(s); | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
167 return AVERROR(EIO); |
0 | 168 } |
169 | |
65 | 170 static int rtp_read(URLContext *h, uint8_t *buf, int size) |
0 | 171 { |
172 RTPContext *s = h->priv_data; | |
173 struct sockaddr_in from; | |
1332 | 174 socklen_t from_len; |
175 int len, fd_max, n; | |
0 | 176 fd_set rfds; |
177 #if 0 | |
178 for(;;) { | |
179 from_len = sizeof(from); | |
180 len = recvfrom (s->rtp_fd, buf, size, 0, | |
181 (struct sockaddr *)&from, &from_len); | |
182 if (len < 0) { | |
2056
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
183 if (ff_neterrno() == FF_NETERROR(EAGAIN) || |
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
184 ff_neterrno() == FF_NETERROR(EINTR)) |
0 | 185 continue; |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
186 return AVERROR(EIO); |
0 | 187 } |
188 break; | |
189 } | |
190 #else | |
191 for(;;) { | |
192 /* build fdset to listen to RTP and RTCP packets */ | |
193 FD_ZERO(&rfds); | |
194 fd_max = s->rtp_fd; | |
195 FD_SET(s->rtp_fd, &rfds); | |
196 if (s->rtcp_fd > fd_max) | |
197 fd_max = s->rtcp_fd; | |
198 FD_SET(s->rtcp_fd, &rfds); | |
199 n = select(fd_max + 1, &rfds, NULL, NULL, NULL); | |
200 if (n > 0) { | |
201 /* first try RTCP */ | |
202 if (FD_ISSET(s->rtcp_fd, &rfds)) { | |
203 from_len = sizeof(from); | |
204 len = recvfrom (s->rtcp_fd, buf, size, 0, | |
205 (struct sockaddr *)&from, &from_len); | |
206 if (len < 0) { | |
2056
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
207 if (ff_neterrno() == FF_NETERROR(EAGAIN) || |
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
208 ff_neterrno() == FF_NETERROR(EINTR)) |
0 | 209 continue; |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
210 return AVERROR(EIO); |
0 | 211 } |
212 break; | |
213 } | |
214 /* then RTP */ | |
215 if (FD_ISSET(s->rtp_fd, &rfds)) { | |
216 from_len = sizeof(from); | |
217 len = recvfrom (s->rtp_fd, buf, size, 0, | |
218 (struct sockaddr *)&from, &from_len); | |
219 if (len < 0) { | |
2056
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
220 if (ff_neterrno() == FF_NETERROR(EAGAIN) || |
eeea52739ff3
use ff_neterrno() and FF_NETERROR() for networking error handling
alex
parents:
1930
diff
changeset
|
221 ff_neterrno() == FF_NETERROR(EINTR)) |
0 | 222 continue; |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2200
diff
changeset
|
223 return AVERROR(EIO); |
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 /** | |
2079 | 270 * Return the local port used by the RTP connection |
0 | 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 }; |