ffmpeg / libavformat / rtsp.c @ 4dcde00c
History | View | Annotate | Download (67.3 KB)
1 | 1617ad97 | Fabrice Bellard | /*
|
---|---|---|---|
2 | 93ced3e8 | Fabrice Bellard | * RTSP/SDP client
|
3 | 406792e7 | Diego Biurrun | * Copyright (c) 2002 Fabrice Bellard
|
4 | 1617ad97 | Fabrice Bellard | *
|
5 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
6 | b78e7197 | Diego Biurrun | *
|
7 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
8 | 1617ad97 | Fabrice Bellard | * modify it under the terms of the GNU Lesser General Public
|
9 | * License as published by the Free Software Foundation; either
|
||
10 | b78e7197 | Diego Biurrun | * version 2.1 of the License, or (at your option) any later version.
|
11 | 1617ad97 | Fabrice Bellard | *
|
12 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
13 | 1617ad97 | Fabrice Bellard | * 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
|
||
18 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
19 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 | 1617ad97 | Fabrice Bellard | */
|
21 | 245976da | Diego Biurrun | |
22 | f9337897 | Ronald S. Bultje | #include "libavutil/base64.h" |
23 | 245976da | Diego Biurrun | #include "libavutil/avstring.h" |
24 | 6a5d31ac | Diego Biurrun | #include "libavutil/intreadwrite.h" |
25 | 9fcae973 | Anton Khirnov | #include "libavutil/parseutils.h" |
26 | f5d33f52 | Josh Allmann | #include "libavutil/random_seed.h" |
27 | 1617ad97 | Fabrice Bellard | #include "avformat.h" |
28 | e731b8d8 | Anton Khirnov | #include "avio_internal.h" |
29 | 1617ad97 | Fabrice Bellard | |
30 | db0ed93e | Marc Hoffman | #include <sys/time.h> |
31 | a8475bbd | Luca Barbato | #if HAVE_POLL_H
|
32 | #include <poll.h> |
||
33 | 6ad1c9c9 | Baptiste Coudurier | #endif
|
34 | ea452b54 | Aurelien Jacobs | #include <strings.h> |
35 | e4a9e3cc | Aurelien Jacobs | #include "internal.h" |
36 | 42572ef5 | Ramiro Polla | #include "network.h" |
37 | cbfa66d0 | Dave Yeo | #include "os_support.h" |
38 | f5d33f52 | Josh Allmann | #include "http.h" |
39 | c971ff19 | Luca Abeni | #include "rtsp.h" |
40 | 1617ad97 | Fabrice Bellard | |
41 | 302879cb | Luca Abeni | #include "rtpdec.h" |
42 | e9dea59f | Ronald S. Bultje | #include "rdt.h" |
43 | 965a3ddb | Martin Storsjö | #include "rtpdec_formats.h" |
44 | a493f80a | Martin Storsjö | #include "rtpenc_chain.h" |
45 | 4934884a | Ryan Martell | |
46 | 1617ad97 | Fabrice Bellard | //#define DEBUG
|
47 | b6892136 | Fabrice Bellard | //#define DEBUG_RTP_TCP
|
48 | 1617ad97 | Fabrice Bellard | |
49 | a8475bbd | Luca Barbato | /* Timeout values for socket poll, in ms,
|
50 | 9cba6f5f | Sam Gerstein | * and read_packet(), in seconds */
|
51 | a8475bbd | Luca Barbato | #define POLL_TIMEOUT_MS 100 |
52 | 9cba6f5f | Sam Gerstein | #define READ_PACKET_TIMEOUT_S 10 |
53 | a8475bbd | Luca Barbato | #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / POLL_TIMEOUT_MS |
54 | 91af5601 | Josh Allmann | #define SDP_MAX_SIZE 16384 |
55 | 96a7c975 | Martin Storsjö | #define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH |
56 | 9cba6f5f | Sam Gerstein | |
57 | 1ef36a70 | Ronald S. Bultje | static void get_word_until_chars(char *buf, int buf_size, |
58 | const char *sep, const char **pp) |
||
59 | 1617ad97 | Fabrice Bellard | { |
60 | const char *p; |
||
61 | char *q;
|
||
62 | |||
63 | p = *pp; |
||
64 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
65 | 1617ad97 | Fabrice Bellard | q = buf; |
66 | while (!strchr(sep, *p) && *p != '\0') { |
||
67 | if ((q - buf) < buf_size - 1) |
||
68 | *q++ = *p; |
||
69 | p++; |
||
70 | } |
||
71 | if (buf_size > 0) |
||
72 | *q = '\0';
|
||
73 | *pp = p; |
||
74 | } |
||
75 | |||
76 | 1ef36a70 | Ronald S. Bultje | static void get_word_sep(char *buf, int buf_size, const char *sep, |
77 | const char **pp) |
||
78 | 1617ad97 | Fabrice Bellard | { |
79 | 1ef36a70 | Ronald S. Bultje | if (**pp == '/') (*pp)++; |
80 | get_word_until_chars(buf, buf_size, sep, pp); |
||
81 | } |
||
82 | 1617ad97 | Fabrice Bellard | |
83 | 1ef36a70 | Ronald S. Bultje | static void get_word(char *buf, int buf_size, const char **pp) |
84 | { |
||
85 | get_word_until_chars(buf, buf_size, SPACE_CHARS, pp); |
||
86 | 1617ad97 | Fabrice Bellard | } |
87 | |||
88 | 8bf0f969 | Martin Storsjö | /** Parse a string p in the form of Range:npt=xx-xx, and determine the start
|
89 | * and end time.
|
||
90 | * Used for seeking in the rtp stream.
|
||
91 | */
|
||
92 | static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) |
||
93 | { |
||
94 | char buf[256]; |
||
95 | |||
96 | p += strspn(p, SPACE_CHARS); |
||
97 | if (!av_stristart(p, "npt=", &p)) |
||
98 | return;
|
||
99 | |||
100 | *start = AV_NOPTS_VALUE; |
||
101 | *end = AV_NOPTS_VALUE; |
||
102 | |||
103 | get_word_sep(buf, sizeof(buf), "-", &p); |
||
104 | 9fcae973 | Anton Khirnov | av_parse_time(start, buf, 1);
|
105 | 8bf0f969 | Martin Storsjö | if (*p == '-') { |
106 | p++; |
||
107 | get_word_sep(buf, sizeof(buf), "-", &p); |
||
108 | 9fcae973 | Anton Khirnov | av_parse_time(end, buf, 1);
|
109 | 8bf0f969 | Martin Storsjö | } |
110 | // av_log(NULL, AV_LOG_DEBUG, "Range Start: %lld\n", *start);
|
||
111 | // av_log(NULL, AV_LOG_DEBUG, "Range End: %lld\n", *end);
|
||
112 | } |
||
113 | |||
114 | static int get_sockaddr(const char *buf, struct sockaddr_storage *sock) |
||
115 | { |
||
116 | struct addrinfo hints, *ai = NULL; |
||
117 | memset(&hints, 0, sizeof(hints)); |
||
118 | hints.ai_flags = AI_NUMERICHOST; |
||
119 | if (getaddrinfo(buf, NULL, &hints, &ai)) |
||
120 | return -1; |
||
121 | memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen));
|
||
122 | freeaddrinfo(ai); |
||
123 | return 0; |
||
124 | } |
||
125 | |||
126 | 44b70ce5 | Martin Storsjö | #if CONFIG_RTPDEC
|
127 | 003eb642 | Martin Storsjö | static void init_rtp_handler(RTPDynamicProtocolHandler *handler, |
128 | RTSPStream *rtsp_st, AVCodecContext *codec) |
||
129 | { |
||
130 | if (!handler)
|
||
131 | return;
|
||
132 | codec->codec_id = handler->codec_id; |
||
133 | rtsp_st->dynamic_handler = handler; |
||
134 | if (handler->open)
|
||
135 | rtsp_st->dynamic_protocol_context = handler->open(); |
||
136 | } |
||
137 | |||
138 | c8965800 | Ronald S. Bultje | /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */
|
139 | 8f3c87f3 | Ronald S. Bultje | static int sdp_parse_rtpmap(AVFormatContext *s, |
140 | 86b6e387 | Martin Storsjö | AVStream *st, RTSPStream *rtsp_st, |
141 | c8965800 | Ronald S. Bultje | int payload_type, const char *p) |
142 | 93ced3e8 | Fabrice Bellard | { |
143 | 86b6e387 | Martin Storsjö | AVCodecContext *codec = st->codec; |
144 | 93ced3e8 | Fabrice Bellard | char buf[256]; |
145 | d1ccf0e0 | Romain Degez | int i;
|
146 | AVCodec *c; |
||
147 | 7b49ce2e | Stefan Huehner | const char *c_name; |
148 | 93ced3e8 | Fabrice Bellard | |
149 | d1ccf0e0 | Romain Degez | /* Loop into AVRtpDynamicPayloadTypes[] and AVRtpPayloadTypes[] and
|
150 | 9d50d396 | Ronald S. Bultje | * see if we can handle this kind of payload.
|
151 | * The space should normally not be there but some Real streams or
|
||
152 | * particular servers ("RealServer Version 6.1.3.970", see issue 1658)
|
||
153 | * have a trailing space. */
|
||
154 | get_word_sep(buf, sizeof(buf), "/ ", &p); |
||
155 | d1ccf0e0 | Romain Degez | if (payload_type >= RTP_PT_PRIVATE) {
|
156 | 003eb642 | Martin Storsjö | RTPDynamicProtocolHandler *handler = |
157 | ff_rtp_handler_find_by_name(buf, codec->codec_type); |
||
158 | init_rtp_handler(handler, rtsp_st, codec); |
||
159 | 160918d5 | Martin Storsjö | /* If no dynamic handler was found, check with the list of standard
|
160 | * allocated types, if such a stream for some reason happens to
|
||
161 | * use a private payload type. This isn't handled in rtpdec.c, since
|
||
162 | * the format name from the rtpmap line never is passed into rtpdec. */
|
||
163 | if (!rtsp_st->dynamic_handler)
|
||
164 | codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type); |
||
165 | 93ced3e8 | Fabrice Bellard | } else {
|
166 | c8965800 | Ronald S. Bultje | /* We are in a standard case
|
167 | * (from http://www.iana.org/assignments/rtp-parameters). */
|
||
168 | d1ccf0e0 | Romain Degez | /* search into AVRtpPayloadTypes[] */
|
169 | 7ed19d7f | Luca Abeni | codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type); |
170 | d1ccf0e0 | Romain Degez | } |
171 | |||
172 | c = avcodec_find_decoder(codec->codec_id); |
||
173 | if (c && c->name)
|
||
174 | 7b49ce2e | Stefan Huehner | c_name = c->name; |
175 | d1ccf0e0 | Romain Degez | else
|
176 | 170870b7 | Ronald S. Bultje | c_name = "(null)";
|
177 | d1ccf0e0 | Romain Degez | |
178 | 7515ed0c | Ronald S. Bultje | get_word_sep(buf, sizeof(buf), "/", &p); |
179 | i = atoi(buf); |
||
180 | switch (codec->codec_type) {
|
||
181 | 72415b2a | Stefano Sabatini | case AVMEDIA_TYPE_AUDIO:
|
182 | 7515ed0c | Ronald S. Bultje | av_log(s, AV_LOG_DEBUG, "audio codec set to: %s\n", c_name);
|
183 | codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE; |
||
184 | codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS; |
||
185 | if (i > 0) { |
||
186 | codec->sample_rate = i; |
||
187 | 86b6e387 | Martin Storsjö | av_set_pts_info(st, 32, 1, codec->sample_rate); |
188 | 7515ed0c | Ronald S. Bultje | get_word_sep(buf, sizeof(buf), "/", &p); |
189 | i = atoi(buf); |
||
190 | if (i > 0) |
||
191 | codec->channels = i; |
||
192 | // TODO: there is a bug here; if it is a mono stream, and
|
||
193 | // less than 22000Hz, faad upconverts to stereo and twice
|
||
194 | // the frequency. No problem, but the sample rate is being
|
||
195 | // set here by the sdp line. Patch on its way. (rdm)
|
||
196 | d1ccf0e0 | Romain Degez | } |
197 | 7515ed0c | Ronald S. Bultje | av_log(s, AV_LOG_DEBUG, "audio samplerate set to: %i\n",
|
198 | codec->sample_rate); |
||
199 | av_log(s, AV_LOG_DEBUG, "audio channels set to: %i\n",
|
||
200 | codec->channels); |
||
201 | break;
|
||
202 | 72415b2a | Stefano Sabatini | case AVMEDIA_TYPE_VIDEO:
|
203 | 7515ed0c | Ronald S. Bultje | av_log(s, AV_LOG_DEBUG, "video codec set to: %s\n", c_name);
|
204 | 86b6e387 | Martin Storsjö | if (i > 0) |
205 | av_set_pts_info(st, 32, 1, i); |
||
206 | 7515ed0c | Ronald S. Bultje | break;
|
207 | default:
|
||
208 | break;
|
||
209 | } |
||
210 | return 0; |
||
211 | 93ced3e8 | Fabrice Bellard | } |
212 | |||
213 | c2bfd816 | Reimar Döffinger | /* parse the attribute line from the fmtp a line of an sdp response. This
|
214 | c8965800 | Ronald S. Bultje | * is broken out as a function because it is used in rtp_h264.c, which is
|
215 | * forthcoming. */
|
||
216 | 3307e6ea | Ronald S. Bultje | int ff_rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, |
217 | 93993933 | Martin Storsjö | char *value, int value_size) |
218 | d0deedcb | Ryan Martell | { |
219 | 30619e6e | Josh Allmann | *p += strspn(*p, SPACE_CHARS); |
220 | c8965800 | Ronald S. Bultje | if (**p) {
|
221 | d0deedcb | Ryan Martell | get_word_sep(attr, attr_size, "=", p);
|
222 | if (**p == '=') |
||
223 | (*p)++; |
||
224 | get_word_sep(value, value_size, ";", p);
|
||
225 | if (**p == ';') |
||
226 | (*p)++; |
||
227 | return 1; |
||
228 | } |
||
229 | return 0; |
||
230 | } |
||
231 | |||
232 | 93ced3e8 | Fabrice Bellard | typedef struct SDPParseState { |
233 | /* SDP only */
|
||
234 | 3fbd12d1 | Martin Storsjö | struct sockaddr_storage default_ip;
|
235 | c8965800 | Ronald S. Bultje | int default_ttl;
|
236 | int skip_media; ///< set if an unknown m= line occurs |
||
237 | 93ced3e8 | Fabrice Bellard | } SDPParseState; |
238 | |||
239 | static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, |
||
240 | 1617ad97 | Fabrice Bellard | int letter, const char *buf) |
241 | { |
||
242 | 8b1ab7bf | Fabrice Bellard | RTSPState *rt = s->priv_data; |
243 | 1617ad97 | Fabrice Bellard | char buf1[64], st_type[64]; |
244 | const char *p; |
||
245 | 72415b2a | Stefano Sabatini | enum AVMediaType codec_type;
|
246 | fb65d2ca | Diego Pettenò | int payload_type, i;
|
247 | 1617ad97 | Fabrice Bellard | AVStream *st; |
248 | RTSPStream *rtsp_st; |
||
249 | 3fbd12d1 | Martin Storsjö | struct sockaddr_storage sdp_ip;
|
250 | 93ced3e8 | Fabrice Bellard | int ttl;
|
251 | |||
252 | dfd2a005 | Luca Barbato | av_dlog(s, "sdp: %c='%s'\n", letter, buf);
|
253 | 1617ad97 | Fabrice Bellard | |
254 | p = buf; |
||
255 | cb760a47 | Ronald S. Bultje | if (s1->skip_media && letter != 'm') |
256 | return;
|
||
257 | c8965800 | Ronald S. Bultje | switch (letter) {
|
258 | 93ced3e8 | Fabrice Bellard | case 'c': |
259 | get_word(buf1, sizeof(buf1), &p);
|
||
260 | if (strcmp(buf1, "IN") != 0) |
||
261 | return;
|
||
262 | get_word(buf1, sizeof(buf1), &p);
|
||
263 | 3fbd12d1 | Martin Storsjö | if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6")) |
264 | 93ced3e8 | Fabrice Bellard | return;
|
265 | get_word_sep(buf1, sizeof(buf1), "/", &p); |
||
266 | 3fbd12d1 | Martin Storsjö | if (get_sockaddr(buf1, &sdp_ip))
|
267 | 93ced3e8 | Fabrice Bellard | return;
|
268 | ttl = 16;
|
||
269 | if (*p == '/') { |
||
270 | p++; |
||
271 | get_word_sep(buf1, sizeof(buf1), "/", &p); |
||
272 | ttl = atoi(buf1); |
||
273 | } |
||
274 | if (s->nb_streams == 0) { |
||
275 | s1->default_ip = sdp_ip; |
||
276 | s1->default_ttl = ttl; |
||
277 | } else {
|
||
278 | d9c0510e | Martin Storsjö | rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
|
279 | 93ced3e8 | Fabrice Bellard | rtsp_st->sdp_ip = sdp_ip; |
280 | rtsp_st->sdp_ttl = ttl; |
||
281 | } |
||
282 | break;
|
||
283 | 1617ad97 | Fabrice Bellard | case 's': |
284 | 2ef6c124 | Stefano Sabatini | av_metadata_set2(&s->metadata, "title", p, 0); |
285 | 1617ad97 | Fabrice Bellard | break;
|
286 | case 'i': |
||
287 | if (s->nb_streams == 0) { |
||
288 | 2ef6c124 | Stefano Sabatini | av_metadata_set2(&s->metadata, "comment", p, 0); |
289 | 1617ad97 | Fabrice Bellard | break;
|
290 | } |
||
291 | break;
|
||
292 | case 'm': |
||
293 | /* new stream */
|
||
294 | cb760a47 | Ronald S. Bultje | s1->skip_media = 0;
|
295 | 1617ad97 | Fabrice Bellard | get_word(st_type, sizeof(st_type), &p);
|
296 | if (!strcmp(st_type, "audio")) { |
||
297 | 72415b2a | Stefano Sabatini | codec_type = AVMEDIA_TYPE_AUDIO; |
298 | 1617ad97 | Fabrice Bellard | } else if (!strcmp(st_type, "video")) { |
299 | 72415b2a | Stefano Sabatini | codec_type = AVMEDIA_TYPE_VIDEO; |
300 | 090438cc | Ronald S. Bultje | } else if (!strcmp(st_type, "application")) { |
301 | 72415b2a | Stefano Sabatini | codec_type = AVMEDIA_TYPE_DATA; |
302 | 1617ad97 | Fabrice Bellard | } else {
|
303 | cb760a47 | Ronald S. Bultje | s1->skip_media = 1;
|
304 | 1617ad97 | Fabrice Bellard | return;
|
305 | } |
||
306 | rtsp_st = av_mallocz(sizeof(RTSPStream));
|
||
307 | if (!rtsp_st)
|
||
308 | return;
|
||
309 | 8b1ab7bf | Fabrice Bellard | rtsp_st->stream_index = -1;
|
310 | dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); |
||
311 | 93ced3e8 | Fabrice Bellard | |
312 | rtsp_st->sdp_ip = s1->default_ip; |
||
313 | rtsp_st->sdp_ttl = s1->default_ttl; |
||
314 | |||
315 | get_word(buf1, sizeof(buf1), &p); /* port */ |
||
316 | rtsp_st->sdp_port = atoi(buf1); |
||
317 | |||
318 | get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */ |
||
319 | 115329f1 | Diego Biurrun | |
320 | 93ced3e8 | Fabrice Bellard | /* XXX: handle list of formats */
|
321 | get_word(buf1, sizeof(buf1), &p); /* format list */ |
||
322 | rtsp_st->sdp_payload_type = atoi(buf1); |
||
323 | |||
324 | 7ed19d7f | Luca Abeni | if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { |
325 | 8b1ab7bf | Fabrice Bellard | /* no corresponding stream */
|
326 | } else {
|
||
327 | b2dd842d | Martin Storsjö | st = av_new_stream(s, rt->nb_rtsp_streams - 1);
|
328 | 8b1ab7bf | Fabrice Bellard | if (!st)
|
329 | return;
|
||
330 | rtsp_st->stream_index = st->index; |
||
331 | 01f4895c | Michael Niedermayer | st->codec->codec_type = codec_type; |
332 | d1ccf0e0 | Romain Degez | if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
|
333 | 6a7e31a9 | Martin Storsjö | RTPDynamicProtocolHandler *handler; |
334 | 8b1ab7bf | Fabrice Bellard | /* if standard payload type, we can find the codec right now */
|
335 | bf6d9818 | Luca Abeni | ff_rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type); |
336 | bbd8f547 | Martin Storsjö | if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
|
337 | st->codec->sample_rate > 0)
|
||
338 | 86b6e387 | Martin Storsjö | av_set_pts_info(st, 32, 1, st->codec->sample_rate); |
339 | 6a7e31a9 | Martin Storsjö | /* Even static payload types may need a custom depacketizer */
|
340 | handler = ff_rtp_handler_find_by_id( |
||
341 | rtsp_st->sdp_payload_type, st->codec->codec_type); |
||
342 | init_rtp_handler(handler, rtsp_st, st->codec); |
||
343 | 8b1ab7bf | Fabrice Bellard | } |
344 | } |
||
345 | 1617ad97 | Fabrice Bellard | /* put a default control url */
|
346 | 00eb13e0 | Alan Steremberg | av_strlcpy(rtsp_st->control_url, rt->control_uri, |
347 | c8965800 | Ronald S. Bultje | sizeof(rtsp_st->control_url));
|
348 | 1617ad97 | Fabrice Bellard | break;
|
349 | case 'a': |
||
350 | 00eb13e0 | Alan Steremberg | if (av_strstart(p, "control:", &p)) { |
351 | if (s->nb_streams == 0) { |
||
352 | if (!strncmp(p, "rtsp://", 7)) |
||
353 | av_strlcpy(rt->control_uri, p, |
||
354 | sizeof(rt->control_uri));
|
||
355 | } else {
|
||
356 | 0b6a7ff4 | Martin Storsjö | char proto[32]; |
357 | /* get the control url */
|
||
358 | d9c0510e | Martin Storsjö | rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
|
359 | 115329f1 | Diego Biurrun | |
360 | 0b6a7ff4 | Martin Storsjö | /* XXX: may need to add full url resolution */
|
361 | av_url_split(proto, sizeof(proto), NULL, 0, NULL, 0, |
||
362 | NULL, NULL, 0, p); |
||
363 | if (proto[0] == '\0') { |
||
364 | /* relative control URL */
|
||
365 | if (rtsp_st->control_url[strlen(rtsp_st->control_url)-1]!='/') |
||
366 | av_strlcat(rtsp_st->control_url, "/",
|
||
367 | sizeof(rtsp_st->control_url));
|
||
368 | av_strlcat(rtsp_st->control_url, p, |
||
369 | sizeof(rtsp_st->control_url));
|
||
370 | } else
|
||
371 | av_strlcpy(rtsp_st->control_url, p, |
||
372 | sizeof(rtsp_st->control_url));
|
||
373 | 00eb13e0 | Alan Steremberg | } |
374 | 83d14c85 | Ronald S. Bultje | } else if (av_strstart(p, "rtpmap:", &p) && s->nb_streams > 0) { |
375 | 93ced3e8 | Fabrice Bellard | /* NOTE: rtpmap is only supported AFTER the 'm=' tag */
|
376 | 115329f1 | Diego Biurrun | get_word(buf1, sizeof(buf1), &p);
|
377 | 93ced3e8 | Fabrice Bellard | payload_type = atoi(buf1); |
378 | 83d14c85 | Ronald S. Bultje | st = s->streams[s->nb_streams - 1];
|
379 | d9c0510e | Martin Storsjö | rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
|
380 | 86b6e387 | Martin Storsjö | sdp_parse_rtpmap(s, st, rtsp_st, payload_type, p); |
381 | 7fc8ac7f | Josh Allmann | } else if (av_strstart(p, "fmtp:", &p) || |
382 | av_strstart(p, "framesize:", &p)) {
|
||
383 | 93ced3e8 | Fabrice Bellard | /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */
|
384 | d0deedcb | Ryan Martell | // let dynamic protocol handlers have a stab at the line.
|
385 | get_word(buf1, sizeof(buf1), &p);
|
||
386 | payload_type = atoi(buf1); |
||
387 | d9c0510e | Martin Storsjö | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
388 | rtsp_st = rt->rtsp_streams[i]; |
||
389 | c8965800 | Ronald S. Bultje | if (rtsp_st->sdp_payload_type == payload_type &&
|
390 | rtsp_st->dynamic_handler && |
||
391 | rtsp_st->dynamic_handler->parse_sdp_a_line) |
||
392 | rtsp_st->dynamic_handler->parse_sdp_a_line(s, i, |
||
393 | rtsp_st->dynamic_protocol_context, buf); |
||
394 | d0deedcb | Ryan Martell | } |
395 | c8965800 | Ronald S. Bultje | } else if (av_strstart(p, "range:", &p)) { |
396 | 31693e00 | Ryan Martell | int64_t start, end; |
397 | |||
398 | // this is so that seeking on a streamed file can work.
|
||
399 | rtsp_parse_range_npt(p, &start, &end); |
||
400 | c8965800 | Ronald S. Bultje | s->start_time = start; |
401 | /* AV_NOPTS_VALUE means live broadcast (and can't seek) */
|
||
402 | s->duration = (end == AV_NOPTS_VALUE) ? |
||
403 | AV_NOPTS_VALUE : end - start; |
||
404 | 119b4668 | Ronald S. Bultje | } else if (av_strstart(p, "IsRealDataType:integer;",&p)) { |
405 | if (atoi(p) == 1) |
||
406 | rt->transport = RTSP_TRANSPORT_RDT; |
||
407 | bb776f3b | Martin Storsjö | } else if (av_strstart(p, "SampleRate:integer;", &p) && |
408 | s->nb_streams > 0) {
|
||
409 | st = s->streams[s->nb_streams - 1];
|
||
410 | st->codec->sample_rate = atoi(p); |
||
411 | 1a30d541 | Ronald S. Bultje | } else {
|
412 | if (rt->server_type == RTSP_SERVER_WMS)
|
||
413 | ff_wms_parse_sdp_a_line(s, p); |
||
414 | if (s->nb_streams > 0) { |
||
415 | c4a3d032 | Ronald S. Bultje | if (rt->server_type == RTSP_SERVER_REAL)
|
416 | ff_real_parse_sdp_a_line(s, s->nb_streams - 1, p);
|
||
417 | |||
418 | d9c0510e | Martin Storsjö | rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
|
419 | c4a3d032 | Ronald S. Bultje | if (rtsp_st->dynamic_handler &&
|
420 | rtsp_st->dynamic_handler->parse_sdp_a_line) |
||
421 | c8965800 | Ronald S. Bultje | rtsp_st->dynamic_handler->parse_sdp_a_line(s, |
422 | s->nb_streams - 1,
|
||
423 | c4a3d032 | Ronald S. Bultje | rtsp_st->dynamic_protocol_context, buf); |
424 | 1a30d541 | Ronald S. Bultje | } |
425 | 1617ad97 | Fabrice Bellard | } |
426 | break;
|
||
427 | } |
||
428 | } |
||
429 | |||
430 | a8475bbd | Luca Barbato | /**
|
431 | * Parse the sdp description and allocate the rtp streams and the
|
||
432 | * pollfd array used for udp ones.
|
||
433 | */
|
||
434 | |||
435 | 0526c6f7 | Martin Storsjö | int ff_sdp_parse(AVFormatContext *s, const char *content) |
436 | 1617ad97 | Fabrice Bellard | { |
437 | a8475bbd | Luca Barbato | RTSPState *rt = s->priv_data; |
438 | 1617ad97 | Fabrice Bellard | const char *p; |
439 | int letter;
|
||
440 | 9211bcdd | Ronald S. Bultje | /* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
|
441 | * contain long SDP lines containing complete ASF Headers (several
|
||
442 | * kB) or arrays of MDPR (RM stream descriptor) headers plus
|
||
443 | * "rulebooks" describing their properties. Therefore, the SDP line
|
||
444 | 373afbaf | Ronald S. Bultje | * buffer is large.
|
445 | *
|
||
446 | afcea58c | Josh Allmann | * The Vorbis FMTP line can be up to 16KB - see xiph_parse_sdp_line
|
447 | * in rtpdec_xiph.c. */
|
||
448 | 373afbaf | Ronald S. Bultje | char buf[16384], *q; |
449 | 93ced3e8 | Fabrice Bellard | SDPParseState sdp_parse_state, *s1 = &sdp_parse_state; |
450 | 115329f1 | Diego Biurrun | |
451 | 93ced3e8 | Fabrice Bellard | memset(s1, 0, sizeof(SDPParseState)); |
452 | 1617ad97 | Fabrice Bellard | p = content; |
453 | c8965800 | Ronald S. Bultje | for (;;) {
|
454 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
455 | 1617ad97 | Fabrice Bellard | letter = *p; |
456 | if (letter == '\0') |
||
457 | break;
|
||
458 | p++; |
||
459 | if (*p != '=') |
||
460 | goto next_line;
|
||
461 | p++; |
||
462 | /* get the content */
|
||
463 | q = buf; |
||
464 | b6892136 | Fabrice Bellard | while (*p != '\n' && *p != '\r' && *p != '\0') { |
465 | 1617ad97 | Fabrice Bellard | if ((q - buf) < sizeof(buf) - 1) |
466 | *q++ = *p; |
||
467 | p++; |
||
468 | } |
||
469 | *q = '\0';
|
||
470 | 93ced3e8 | Fabrice Bellard | sdp_parse_line(s, s1, letter, buf); |
471 | 1617ad97 | Fabrice Bellard | next_line:
|
472 | while (*p != '\n' && *p != '\0') |
||
473 | p++; |
||
474 | if (*p == '\n') |
||
475 | p++; |
||
476 | } |
||
477 | a8475bbd | Luca Barbato | rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1)); |
478 | if (!rt->p) return AVERROR(ENOMEM); |
||
479 | 1617ad97 | Fabrice Bellard | return 0; |
480 | } |
||
481 | 44b70ce5 | Martin Storsjö | #endif /* CONFIG_RTPDEC */ |
482 | 1617ad97 | Fabrice Bellard | |
483 | 93e7490e | Martin Storsjo | void ff_rtsp_undo_setup(AVFormatContext *s)
|
484 | { |
||
485 | RTSPState *rt = s->priv_data; |
||
486 | int i;
|
||
487 | |||
488 | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
||
489 | RTSPStream *rtsp_st = rt->rtsp_streams[i]; |
||
490 | if (!rtsp_st)
|
||
491 | continue;
|
||
492 | if (rtsp_st->transport_priv) {
|
||
493 | if (s->oformat) {
|
||
494 | AVFormatContext *rtpctx = rtsp_st->transport_priv; |
||
495 | av_write_trailer(rtpctx); |
||
496 | if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
|
||
497 | uint8_t *ptr; |
||
498 | 6dc7d80d | Anton Khirnov | avio_close_dyn_buf(rtpctx->pb, &ptr); |
499 | 93e7490e | Martin Storsjo | av_free(ptr); |
500 | } else {
|
||
501 | 22a3212e | Anton Khirnov | avio_close(rtpctx->pb); |
502 | 93e7490e | Martin Storsjo | } |
503 | b22dbb29 | Martin Storsjö | avformat_free_context(rtpctx); |
504 | 93e7490e | Martin Storsjo | } else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) |
505 | ff_rdt_parse_close(rtsp_st->transport_priv); |
||
506 | else if (CONFIG_RTPDEC) |
||
507 | rtp_parse_close(rtsp_st->transport_priv); |
||
508 | } |
||
509 | rtsp_st->transport_priv = NULL;
|
||
510 | if (rtsp_st->rtp_handle)
|
||
511 | url_close(rtsp_st->rtp_handle); |
||
512 | rtsp_st->rtp_handle = NULL;
|
||
513 | } |
||
514 | } |
||
515 | |||
516 | 1ced9da3 | Luca Abeni | /* close and free RTSP streams */
|
517 | 3307e6ea | Ronald S. Bultje | void ff_rtsp_close_streams(AVFormatContext *s)
|
518 | 1ced9da3 | Luca Abeni | { |
519 | 52aa4338 | Martin Storsjö | RTSPState *rt = s->priv_data; |
520 | 1ced9da3 | Luca Abeni | int i;
|
521 | RTSPStream *rtsp_st; |
||
522 | |||
523 | 93e7490e | Martin Storsjo | ff_rtsp_undo_setup(s); |
524 | c8965800 | Ronald S. Bultje | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
525 | 1ced9da3 | Luca Abeni | rtsp_st = rt->rtsp_streams[i]; |
526 | if (rtsp_st) {
|
||
527 | if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
|
||
528 | c8965800 | Ronald S. Bultje | rtsp_st->dynamic_handler->close( |
529 | rtsp_st->dynamic_protocol_context); |
||
530 | ea7f0807 | Luca Barbato | av_free(rtsp_st); |
531 | 1ced9da3 | Luca Abeni | } |
532 | } |
||
533 | av_free(rt->rtsp_streams); |
||
534 | if (rt->asf_ctx) {
|
||
535 | av_close_input_stream (rt->asf_ctx); |
||
536 | rt->asf_ctx = NULL;
|
||
537 | } |
||
538 | a8475bbd | Luca Barbato | av_free(rt->p); |
539 | 96a7c975 | Martin Storsjö | av_free(rt->recvbuf); |
540 | 1ced9da3 | Luca Abeni | } |
541 | |||
542 | c8965800 | Ronald S. Bultje | static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) |
543 | 1ced9da3 | Luca Abeni | { |
544 | RTSPState *rt = s->priv_data; |
||
545 | AVStream *st = NULL;
|
||
546 | |||
547 | /* open the RTP context */
|
||
548 | if (rtsp_st->stream_index >= 0) |
||
549 | st = s->streams[rtsp_st->stream_index]; |
||
550 | if (!st)
|
||
551 | s->ctx_flags |= AVFMTCTX_NOHEADER; |
||
552 | |||
553 | 44b70ce5 | Martin Storsjö | if (s->oformat && CONFIG_RTSP_MUXER) {
|
554 | a493f80a | Martin Storsjö | rtsp_st->transport_priv = ff_rtp_chain_mux_open(s, st, |
555 | rtsp_st->rtp_handle, |
||
556 | RTSP_TCP_MAX_PACKET_SIZE); |
||
557 | c2bfd816 | Reimar Döffinger | /* Ownership of rtp_handle is passed to the rtp mux context */
|
558 | fd450a51 | Martin Storsjö | rtsp_st->rtp_handle = NULL;
|
559 | 44b70ce5 | Martin Storsjö | } else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) |
560 | 1ced9da3 | Luca Abeni | rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, |
561 | rtsp_st->dynamic_protocol_context, |
||
562 | rtsp_st->dynamic_handler); |
||
563 | 44b70ce5 | Martin Storsjö | else if (CONFIG_RTPDEC) |
564 | 1ced9da3 | Luca Abeni | rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle, |
565 | 58ee0991 | Martin Storsjö | rtsp_st->sdp_payload_type, |
566 | (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay) |
||
567 | ? 0 : RTP_REORDER_QUEUE_DEFAULT_SIZE);
|
||
568 | 1ced9da3 | Luca Abeni | |
569 | if (!rtsp_st->transport_priv) {
|
||
570 | return AVERROR(ENOMEM);
|
||
571 | 44b70ce5 | Martin Storsjö | } else if (rt->transport != RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) { |
572 | c8965800 | Ronald S. Bultje | if (rtsp_st->dynamic_handler) {
|
573 | 1ced9da3 | Luca Abeni | rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, |
574 | rtsp_st->dynamic_protocol_context, |
||
575 | rtsp_st->dynamic_handler); |
||
576 | } |
||
577 | } |
||
578 | |||
579 | return 0; |
||
580 | } |
||
581 | |||
582 | 6f5a3d0a | Martin Storsjö | #if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER
|
583 | 1617ad97 | Fabrice Bellard | static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) |
584 | { |
||
585 | const char *p; |
||
586 | int v;
|
||
587 | |||
588 | p = *pp; |
||
589 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
590 | 1617ad97 | Fabrice Bellard | v = strtol(p, (char **)&p, 10); |
591 | if (*p == '-') { |
||
592 | p++; |
||
593 | *min_ptr = v; |
||
594 | v = strtol(p, (char **)&p, 10); |
||
595 | *max_ptr = v; |
||
596 | } else {
|
||
597 | *min_ptr = v; |
||
598 | *max_ptr = v; |
||
599 | } |
||
600 | *pp = p; |
||
601 | } |
||
602 | |||
603 | /* XXX: only one transport specification is parsed */
|
||
604 | a9e534d5 | Ronald S. Bultje | static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p) |
605 | 1617ad97 | Fabrice Bellard | { |
606 | char transport_protocol[16]; |
||
607 | char profile[16]; |
||
608 | char lower_transport[16]; |
||
609 | char parameter[16]; |
||
610 | RTSPTransportField *th; |
||
611 | char buf[256]; |
||
612 | 115329f1 | Diego Biurrun | |
613 | 1617ad97 | Fabrice Bellard | reply->nb_transports = 0;
|
614 | 115329f1 | Diego Biurrun | |
615 | c8965800 | Ronald S. Bultje | for (;;) {
|
616 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
617 | 1617ad97 | Fabrice Bellard | if (*p == '\0') |
618 | break;
|
||
619 | |||
620 | th = &reply->transports[reply->nb_transports]; |
||
621 | |||
622 | 115329f1 | Diego Biurrun | get_word_sep(transport_protocol, sizeof(transport_protocol),
|
623 | 1617ad97 | Fabrice Bellard | "/", &p);
|
624 | e1502118 | Luca Barbato | if (!strcasecmp (transport_protocol, "rtp")) { |
625 | 7ecc634e | Luca Barbato | get_word_sep(profile, sizeof(profile), "/;,", &p); |
626 | lower_transport[0] = '\0'; |
||
627 | /* rtp/avp/<protocol> */
|
||
628 | if (*p == '/') { |
||
629 | get_word_sep(lower_transport, sizeof(lower_transport),
|
||
630 | ";,", &p);
|
||
631 | 119b4668 | Ronald S. Bultje | } |
632 | th->transport = RTSP_TRANSPORT_RTP; |
||
633 | } else if (!strcasecmp (transport_protocol, "x-pn-tng") || |
||
634 | !strcasecmp (transport_protocol, "x-real-rdt")) {
|
||
635 | 7ecc634e | Luca Barbato | /* x-pn-tng/<protocol> */
|
636 | e1502118 | Luca Barbato | get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p); |
637 | profile[0] = '\0'; |
||
638 | 119b4668 | Ronald S. Bultje | th->transport = RTSP_TRANSPORT_RDT; |
639 | 1617ad97 | Fabrice Bellard | } |
640 | b6892136 | Fabrice Bellard | if (!strcasecmp(lower_transport, "TCP")) |
641 | 90abbdba | Ronald S. Bultje | th->lower_transport = RTSP_LOWER_TRANSPORT_TCP; |
642 | 1617ad97 | Fabrice Bellard | else
|
643 | 90abbdba | Ronald S. Bultje | th->lower_transport = RTSP_LOWER_TRANSPORT_UDP; |
644 | 115329f1 | Diego Biurrun | |
645 | 1617ad97 | Fabrice Bellard | if (*p == ';') |
646 | p++; |
||
647 | /* get each parameter */
|
||
648 | while (*p != '\0' && *p != ',') { |
||
649 | get_word_sep(parameter, sizeof(parameter), "=;,", &p); |
||
650 | if (!strcmp(parameter, "port")) { |
||
651 | if (*p == '=') { |
||
652 | p++; |
||
653 | rtsp_parse_range(&th->port_min, &th->port_max, &p); |
||
654 | } |
||
655 | } else if (!strcmp(parameter, "client_port")) { |
||
656 | if (*p == '=') { |
||
657 | p++; |
||
658 | 115329f1 | Diego Biurrun | rtsp_parse_range(&th->client_port_min, |
659 | 1617ad97 | Fabrice Bellard | &th->client_port_max, &p); |
660 | } |
||
661 | } else if (!strcmp(parameter, "server_port")) { |
||
662 | if (*p == '=') { |
||
663 | p++; |
||
664 | 115329f1 | Diego Biurrun | rtsp_parse_range(&th->server_port_min, |
665 | 1617ad97 | Fabrice Bellard | &th->server_port_max, &p); |
666 | } |
||
667 | } else if (!strcmp(parameter, "interleaved")) { |
||
668 | if (*p == '=') { |
||
669 | p++; |
||
670 | 115329f1 | Diego Biurrun | rtsp_parse_range(&th->interleaved_min, |
671 | 1617ad97 | Fabrice Bellard | &th->interleaved_max, &p); |
672 | } |
||
673 | } else if (!strcmp(parameter, "multicast")) { |
||
674 | 90abbdba | Ronald S. Bultje | if (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP)
|
675 | th->lower_transport = RTSP_LOWER_TRANSPORT_UDP_MULTICAST; |
||
676 | 1617ad97 | Fabrice Bellard | } else if (!strcmp(parameter, "ttl")) { |
677 | if (*p == '=') { |
||
678 | p++; |
||
679 | th->ttl = strtol(p, (char **)&p, 10); |
||
680 | } |
||
681 | } else if (!strcmp(parameter, "destination")) { |
||
682 | if (*p == '=') { |
||
683 | p++; |
||
684 | get_word_sep(buf, sizeof(buf), ";,", &p); |
||
685 | 7934b15d | Martin Storsjö | get_sockaddr(buf, &th->destination); |
686 | 1617ad97 | Fabrice Bellard | } |
687 | 619298a8 | John Wimer | } else if (!strcmp(parameter, "source")) { |
688 | if (*p == '=') { |
||
689 | p++; |
||
690 | get_word_sep(buf, sizeof(buf), ";,", &p); |
||
691 | av_strlcpy(th->source, buf, sizeof(th->source));
|
||
692 | } |
||
693 | 1617ad97 | Fabrice Bellard | } |
694 | 619298a8 | John Wimer | |
695 | 1617ad97 | Fabrice Bellard | while (*p != ';' && *p != '\0' && *p != ',') |
696 | p++; |
||
697 | if (*p == ';') |
||
698 | p++; |
||
699 | } |
||
700 | if (*p == ',') |
||
701 | p++; |
||
702 | |||
703 | reply->nb_transports++; |
||
704 | } |
||
705 | } |
||
706 | |||
707 | 29db7c3a | Martin Storsjö | static void handle_rtp_info(RTSPState *rt, const char *url, |
708 | uint32_t seq, uint32_t rtptime) |
||
709 | { |
||
710 | int i;
|
||
711 | if (!rtptime || !url[0]) |
||
712 | return;
|
||
713 | if (rt->transport != RTSP_TRANSPORT_RTP)
|
||
714 | return;
|
||
715 | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
||
716 | RTSPStream *rtsp_st = rt->rtsp_streams[i]; |
||
717 | RTPDemuxContext *rtpctx = rtsp_st->transport_priv; |
||
718 | if (!rtpctx)
|
||
719 | continue;
|
||
720 | if (!strcmp(rtsp_st->control_url, url)) {
|
||
721 | rtpctx->base_timestamp = rtptime; |
||
722 | break;
|
||
723 | } |
||
724 | } |
||
725 | } |
||
726 | |||
727 | static void rtsp_parse_rtp_info(RTSPState *rt, const char *p) |
||
728 | { |
||
729 | int read = 0; |
||
730 | char key[20], value[1024], url[1024] = ""; |
||
731 | uint32_t seq = 0, rtptime = 0; |
||
732 | |||
733 | for (;;) {
|
||
734 | p += strspn(p, SPACE_CHARS); |
||
735 | if (!*p)
|
||
736 | break;
|
||
737 | get_word_sep(key, sizeof(key), "=", &p); |
||
738 | if (*p != '=') |
||
739 | break;
|
||
740 | p++; |
||
741 | get_word_sep(value, sizeof(value), ";, ", &p); |
||
742 | read++; |
||
743 | if (!strcmp(key, "url")) |
||
744 | av_strlcpy(url, value, sizeof(url));
|
||
745 | else if (!strcmp(key, "seq")) |
||
746 | seq = strtol(value, NULL, 10); |
||
747 | else if (!strcmp(key, "rtptime")) |
||
748 | rtptime = strtol(value, NULL, 10); |
||
749 | if (*p == ',') { |
||
750 | handle_rtp_info(rt, url, seq, rtptime); |
||
751 | url[0] = '\0'; |
||
752 | seq = rtptime = 0;
|
||
753 | read = 0;
|
||
754 | } |
||
755 | if (*p)
|
||
756 | p++; |
||
757 | } |
||
758 | if (read > 0) |
||
759 | handle_rtp_info(rt, url, seq, rtptime); |
||
760 | } |
||
761 | |||
762 | 2626308a | Martin Storsjö | void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, |
763 | 77223c53 | Martin Storsjö | RTSPState *rt, const char *method) |
764 | 1617ad97 | Fabrice Bellard | { |
765 | const char *p; |
||
766 | |||
767 | /* NOTE: we do case independent match for broken servers */
|
||
768 | p = buf; |
||
769 | f7d78f36 | Måns Rullgård | if (av_stristart(p, "Session:", &p)) { |
770 | 30e79845 | Ronald S. Bultje | int t;
|
771 | 1617ad97 | Fabrice Bellard | get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); |
772 | 30e79845 | Ronald S. Bultje | if (av_stristart(p, ";timeout=", &p) && |
773 | (t = strtol(p, NULL, 10)) > 0) { |
||
774 | reply->timeout = t; |
||
775 | } |
||
776 | f7d78f36 | Måns Rullgård | } else if (av_stristart(p, "Content-Length:", &p)) { |
777 | 1617ad97 | Fabrice Bellard | reply->content_length = strtol(p, NULL, 10); |
778 | f7d78f36 | Måns Rullgård | } else if (av_stristart(p, "Transport:", &p)) { |
779 | 1617ad97 | Fabrice Bellard | rtsp_parse_transport(reply, p); |
780 | f7d78f36 | Måns Rullgård | } else if (av_stristart(p, "CSeq:", &p)) { |
781 | 1617ad97 | Fabrice Bellard | reply->seq = strtol(p, NULL, 10); |
782 | f7d78f36 | Måns Rullgård | } else if (av_stristart(p, "Range:", &p)) { |
783 | 31693e00 | Ryan Martell | rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end); |
784 | 30aa6aed | Ronald S. Bultje | } else if (av_stristart(p, "RealChallenge1:", &p)) { |
785 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
786 | 30aa6aed | Ronald S. Bultje | av_strlcpy(reply->real_challenge, p, sizeof(reply->real_challenge));
|
787 | 7a86bafa | Ronald S. Bultje | } else if (av_stristart(p, "Server:", &p)) { |
788 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
789 | 7a86bafa | Ronald S. Bultje | av_strlcpy(reply->server, p, sizeof(reply->server));
|
790 | fccb1770 | Ronald S. Bultje | } else if (av_stristart(p, "Notice:", &p) || |
791 | av_stristart(p, "X-Notice:", &p)) {
|
||
792 | reply->notice = strtol(p, NULL, 10); |
||
793 | d243ba30 | Luca Barbato | } else if (av_stristart(p, "Location:", &p)) { |
794 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
795 | d243ba30 | Luca Barbato | av_strlcpy(reply->location, p , sizeof(reply->location));
|
796 | acc9ed14 | Martin Storsjö | } else if (av_stristart(p, "WWW-Authenticate:", &p) && rt) { |
797 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
798 | acc9ed14 | Martin Storsjö | ff_http_auth_handle_header(&rt->auth_state, "WWW-Authenticate", p);
|
799 | } else if (av_stristart(p, "Authentication-Info:", &p) && rt) { |
||
800 | 30619e6e | Josh Allmann | p += strspn(p, SPACE_CHARS); |
801 | acc9ed14 | Martin Storsjö | ff_http_auth_handle_header(&rt->auth_state, "Authentication-Info", p);
|
802 | d2995eb9 | Martin Storsjö | } else if (av_stristart(p, "Content-Base:", &p) && rt) { |
803 | dd22cfb1 | Martin Storsjö | p += strspn(p, SPACE_CHARS); |
804 | d2995eb9 | Martin Storsjö | if (method && !strcmp(method, "DESCRIBE")) |
805 | av_strlcpy(rt->control_uri, p , sizeof(rt->control_uri));
|
||
806 | 29db7c3a | Martin Storsjö | } else if (av_stristart(p, "RTP-Info:", &p) && rt) { |
807 | p += strspn(p, SPACE_CHARS); |
||
808 | if (method && !strcmp(method, "PLAY")) |
||
809 | rtsp_parse_rtp_info(rt, p); |
||
810 | 1617ad97 | Fabrice Bellard | } |
811 | } |
||
812 | |||
813 | b7b8fc34 | Fabrice Bellard | /* skip a RTP/TCP interleaved packet */
|
814 | ec55edba | Martin Storsjö | void ff_rtsp_skip_packet(AVFormatContext *s)
|
815 | b7b8fc34 | Fabrice Bellard | { |
816 | RTSPState *rt = s->priv_data; |
||
817 | int ret, len, len1;
|
||
818 | uint8_t buf[1024];
|
||
819 | |||
820 | 0e848977 | Kostya Shishkov | ret = url_read_complete(rt->rtsp_hd, buf, 3);
|
821 | b7b8fc34 | Fabrice Bellard | if (ret != 3) |
822 | return;
|
||
823 | 80fb8234 | Ronald S. Bultje | len = AV_RB16(buf + 1);
|
824 | 67c9cd69 | Baptiste Coudurier | |
825 | dfd2a005 | Luca Barbato | av_dlog(s, "skipping RTP packet len=%d\n", len);
|
826 | 67c9cd69 | Baptiste Coudurier | |
827 | b7b8fc34 | Fabrice Bellard | /* skip payload */
|
828 | while (len > 0) { |
||
829 | len1 = len; |
||
830 | if (len1 > sizeof(buf)) |
||
831 | len1 = sizeof(buf);
|
||
832 | 0e848977 | Kostya Shishkov | ret = url_read_complete(rt->rtsp_hd, buf, len1); |
833 | b7b8fc34 | Fabrice Bellard | if (ret != len1)
|
834 | return;
|
||
835 | len -= len1; |
||
836 | } |
||
837 | } |
||
838 | 1617ad97 | Fabrice Bellard | |
839 | 3307e6ea | Ronald S. Bultje | int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
|
840 | 93993933 | Martin Storsjö | unsigned char **content_ptr, |
841 | 3df54c6b | Martin Storsjö | int return_on_interleaved_data, const char *method) |
842 | 1617ad97 | Fabrice Bellard | { |
843 | RTSPState *rt = s->priv_data; |
||
844 | char buf[4096], buf1[1024], *q; |
||
845 | unsigned char ch; |
||
846 | const char *p; |
||
847 | 7e726132 | Ronald S. Bultje | int ret, content_length, line_count = 0; |
848 | 1617ad97 | Fabrice Bellard | unsigned char *content = NULL; |
849 | |||
850 | d541a7d2 | Ronald S. Bultje | memset(reply, 0, sizeof(*reply)); |
851 | 1617ad97 | Fabrice Bellard | |
852 | /* parse reply (XXX: use buffers) */
|
||
853 | rt->last_reply[0] = '\0'; |
||
854 | c8965800 | Ronald S. Bultje | for (;;) {
|
855 | 1617ad97 | Fabrice Bellard | q = buf; |
856 | c8965800 | Ronald S. Bultje | for (;;) {
|
857 | 0e848977 | Kostya Shishkov | ret = url_read_complete(rt->rtsp_hd, &ch, 1);
|
858 | 7e726132 | Ronald S. Bultje | #ifdef DEBUG_RTP_TCP
|
859 | dfd2a005 | Luca Barbato | av_dlog(s, "ret=%d c=%02x [%c]\n", ret, ch, ch);
|
860 | 7e726132 | Ronald S. Bultje | #endif
|
861 | if (ret != 1) |
||
862 | 2401660d | Martin Storsjö | return AVERROR_EOF;
|
863 | 1617ad97 | Fabrice Bellard | if (ch == '\n') |
864 | break;
|
||
865 | b7b8fc34 | Fabrice Bellard | if (ch == '$') { |
866 | /* XXX: only parse it if first char on line ? */
|
||
867 | 7e726132 | Ronald S. Bultje | if (return_on_interleaved_data) {
|
868 | return 1; |
||
869 | } else
|
||
870 | ec55edba | Martin Storsjö | ff_rtsp_skip_packet(s); |
871 | b7b8fc34 | Fabrice Bellard | } else if (ch != '\r') { |
872 | 1617ad97 | Fabrice Bellard | if ((q - buf) < sizeof(buf) - 1) |
873 | *q++ = ch; |
||
874 | } |
||
875 | } |
||
876 | *q = '\0';
|
||
877 | 67c9cd69 | Baptiste Coudurier | |
878 | dfd2a005 | Luca Barbato | av_dlog(s, "line='%s'\n", buf);
|
879 | 67c9cd69 | Baptiste Coudurier | |
880 | 1617ad97 | Fabrice Bellard | /* test if last line */
|
881 | if (buf[0] == '\0') |
||
882 | break;
|
||
883 | p = buf; |
||
884 | if (line_count == 0) { |
||
885 | /* get reply code */
|
||
886 | get_word(buf1, sizeof(buf1), &p);
|
||
887 | get_word(buf1, sizeof(buf1), &p);
|
||
888 | reply->status_code = atoi(buf1); |
||
889 | d93fdcbf | Luca Barbato | av_strlcpy(reply->reason, p, sizeof(reply->reason));
|
890 | 1617ad97 | Fabrice Bellard | } else {
|
891 | 77223c53 | Martin Storsjö | ff_rtsp_parse_line(reply, p, rt, method); |
892 | 75e61b0e | Måns Rullgård | av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
|
893 | av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply)); |
||
894 | 1617ad97 | Fabrice Bellard | } |
895 | line_count++; |
||
896 | } |
||
897 | 115329f1 | Diego Biurrun | |
898 | 1617ad97 | Fabrice Bellard | if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') |
899 | 75e61b0e | Måns Rullgård | av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
|
900 | 115329f1 | Diego Biurrun | |
901 | 1617ad97 | Fabrice Bellard | content_length = reply->content_length; |
902 | if (content_length > 0) { |
||
903 | /* leave some room for a trailing '\0' (useful for simple parsing) */
|
||
904 | content = av_malloc(content_length + 1);
|
||
905 | 0e848977 | Kostya Shishkov | (void)url_read_complete(rt->rtsp_hd, content, content_length);
|
906 | 1617ad97 | Fabrice Bellard | content[content_length] = '\0';
|
907 | } |
||
908 | if (content_ptr)
|
||
909 | *content_ptr = content; |
||
910 | e2e2e7dd | Alex Beregszaszi | else
|
911 | av_free(content); |
||
912 | 7e726132 | Ronald S. Bultje | |
913 | 7ed8211b | Luca Barbato | if (rt->seq != reply->seq) {
|
914 | av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n",
|
||
915 | rt->seq, reply->seq); |
||
916 | } |
||
917 | |||
918 | fccb1770 | Ronald S. Bultje | /* EOS */
|
919 | if (reply->notice == 2101 /* End-of-Stream Reached */ || |
||
920 | reply->notice == 2104 /* Start-of-Stream Reached */ || |
||
921 | c8965800 | Ronald S. Bultje | reply->notice == 2306 /* Continuous Feed Terminated */) { |
922 | fccb1770 | Ronald S. Bultje | rt->state = RTSP_STATE_IDLE; |
923 | c8965800 | Ronald S. Bultje | } else if (reply->notice >= 4400 && reply->notice < 5500) { |
924 | fccb1770 | Ronald S. Bultje | return AVERROR(EIO); /* data or server error */ |
925 | c8965800 | Ronald S. Bultje | } else if (reply->notice == 2401 /* Ticket Expired */ || |
926 | fccb1770 | Ronald S. Bultje | (reply->notice >= 5500 && reply->notice < 5600) /* end of term */ ) |
927 | return AVERROR(EPERM);
|
||
928 | |||
929 | 7e726132 | Ronald S. Bultje | return 0; |
930 | 1617ad97 | Fabrice Bellard | } |
931 | |||
932 | 57c4d01e | Diego Elio Pettenò | /**
|
933 | * Send a command to the RTSP server without waiting for the reply.
|
||
934 | *
|
||
935 | * @param s RTSP (de)muxer context
|
||
936 | * @param method the method for the request
|
||
937 | * @param url the target url for the request
|
||
938 | * @param headers extra header lines to include in the request
|
||
939 | * @param send_content if non-null, the data to send as request body content
|
||
940 | * @param send_content_length the length of the send_content data, or 0 if
|
||
941 | * send_content is null
|
||
942 | *
|
||
943 | * @return zero if success, nonzero otherwise
|
||
944 | */
|
||
945 | static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s, |
||
946 | const char *method, const char *url, |
||
947 | const char *headers, |
||
948 | const unsigned char *send_content, |
||
949 | int send_content_length)
|
||
950 | 29b9f58b | Ronald S. Bultje | { |
951 | RTSPState *rt = s->priv_data; |
||
952 | f5d33f52 | Josh Allmann | char buf[4096], *out_buf; |
953 | char base64buf[AV_BASE64_SIZE(sizeof(buf))]; |
||
954 | 29b9f58b | Ronald S. Bultje | |
955 | f5d33f52 | Josh Allmann | /* Add in RTSP headers */
|
956 | out_buf = buf; |
||
957 | 29b9f58b | Ronald S. Bultje | rt->seq++; |
958 | b17d11c6 | Martin Storsjö | snprintf(buf, sizeof(buf), "%s %s RTSP/1.0\r\n", method, url); |
959 | if (headers)
|
||
960 | av_strlcat(buf, headers, sizeof(buf));
|
||
961 | 7b4a3645 | Martin Storsjö | av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq); |
962 | b17d11c6 | Martin Storsjö | if (rt->session_id[0] != '\0' && (!headers || |
963 | !strstr(headers, "\nIf-Match:"))) {
|
||
964 | 7b4a3645 | Martin Storsjö | av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id); |
965 | 29b9f58b | Ronald S. Bultje | } |
966 | aa8bf2fb | Martin Storsjö | if (rt->auth[0]) { |
967 | char *str = ff_http_auth_create_response(&rt->auth_state,
|
||
968 | rt->auth, url, method); |
||
969 | if (str)
|
||
970 | av_strlcat(buf, str, sizeof(buf));
|
||
971 | av_free(str); |
||
972 | } |
||
973 | dfd017bf | Martin Storsjö | if (send_content_length > 0 && send_content) |
974 | av_strlcatf(buf, sizeof(buf), "Content-Length: %d\r\n", send_content_length); |
||
975 | 29b9f58b | Ronald S. Bultje | av_strlcat(buf, "\r\n", sizeof(buf)); |
976 | 67c9cd69 | Baptiste Coudurier | |
977 | f5d33f52 | Josh Allmann | /* base64 encode rtsp if tunneling */
|
978 | if (rt->control_transport == RTSP_MODE_TUNNEL) {
|
||
979 | av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
|
||
980 | out_buf = base64buf; |
||
981 | } |
||
982 | |||
983 | dfd2a005 | Luca Barbato | av_dlog(s, "Sending:\n%s--\n", buf);
|
984 | 67c9cd69 | Baptiste Coudurier | |
985 | f5d33f52 | Josh Allmann | url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf)); |
986 | if (send_content_length > 0 && send_content) { |
||
987 | if (rt->control_transport == RTSP_MODE_TUNNEL) {
|
||
988 | av_log(s, AV_LOG_ERROR, "tunneling of RTSP requests "
|
||
989 | "with content data not supported\n");
|
||
990 | return AVERROR_PATCHWELCOME;
|
||
991 | } |
||
992 | b8c2c41d | Josh Allmann | url_write(rt->rtsp_hd_out, send_content, send_content_length); |
993 | f5d33f52 | Josh Allmann | } |
994 | 30e79845 | Ronald S. Bultje | rt->last_cmd_time = av_gettime(); |
995 | d0382374 | Josh Allmann | |
996 | return 0; |
||
997 | 30e79845 | Ronald S. Bultje | } |
998 | |||
999 | d0382374 | Josh Allmann | int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method, |
1000 | fc490fcf | Martin Storsjö | const char *url, const char *headers) |
1001 | dfd017bf | Martin Storsjö | { |
1002 | d0382374 | Josh Allmann | return ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0); |
1003 | dfd017bf | Martin Storsjö | } |
1004 | |||
1005 | d0382374 | Josh Allmann | int ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url, |
1006 | fc490fcf | Martin Storsjö | const char *headers, RTSPMessageHeader *reply, |
1007 | unsigned char **content_ptr) |
||
1008 | 30e79845 | Ronald S. Bultje | { |
1009 | d0382374 | Josh Allmann | return ff_rtsp_send_cmd_with_content(s, method, url, headers, reply,
|
1010 | fc490fcf | Martin Storsjö | content_ptr, NULL, 0); |
1011 | 29b9f58b | Ronald S. Bultje | } |
1012 | |||
1013 | d0382374 | Josh Allmann | int ff_rtsp_send_cmd_with_content(AVFormatContext *s,
|
1014 | fc490fcf | Martin Storsjö | const char *method, const char *url, |
1015 | const char *header, |
||
1016 | RTSPMessageHeader *reply, |
||
1017 | unsigned char **content_ptr, |
||
1018 | const unsigned char *send_content, |
||
1019 | int send_content_length)
|
||
1020 | dfd017bf | Martin Storsjö | { |
1021 | 30af0779 | Martin Storsjö | RTSPState *rt = s->priv_data; |
1022 | HTTPAuthType cur_auth_type; |
||
1023 | d0382374 | Josh Allmann | int ret;
|
1024 | 30af0779 | Martin Storsjö | |
1025 | retry:
|
||
1026 | cur_auth_type = rt->auth_state.auth_type; |
||
1027 | d0382374 | Josh Allmann | if ((ret = ff_rtsp_send_cmd_with_content_async(s, method, url, header,
|
1028 | fc490fcf | Martin Storsjö | send_content, |
1029 | send_content_length))) |
||
1030 | d0382374 | Josh Allmann | return ret;
|
1031 | dfd017bf | Martin Storsjö | |
1032 | 3df54c6b | Martin Storsjö | if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0) |
1033 | d0382374 | Josh Allmann | return ret;
|
1034 | 30af0779 | Martin Storsjö | |
1035 | if (reply->status_code == 401 && cur_auth_type == HTTP_AUTH_NONE && |
||
1036 | rt->auth_state.auth_type != HTTP_AUTH_NONE) |
||
1037 | goto retry;
|
||
1038 | d0382374 | Josh Allmann | |
1039 | bf55cf19 | Luca Barbato | if (reply->status_code > 400){ |
1040 | d93fdcbf | Luca Barbato | av_log(s, AV_LOG_ERROR, "method %s failed: %d%s\n",
|
1041 | bf55cf19 | Luca Barbato | method, |
1042 | d93fdcbf | Luca Barbato | reply->status_code, |
1043 | reply->reason); |
||
1044 | bf55cf19 | Luca Barbato | av_log(s, AV_LOG_DEBUG, "%s\n", rt->last_reply);
|
1045 | } |
||
1046 | |||
1047 | d0382374 | Josh Allmann | return 0; |
1048 | dfd017bf | Martin Storsjö | } |
1049 | |||
1050 | 53620bba | Ronald S. Bultje | /**
|
1051 | 32e543f8 | Benoit Fouet | * @return 0 on success, <0 on error, 1 if protocol is unavailable.
|
1052 | 53620bba | Ronald S. Bultje | */
|
1053 | fef5649a | Martin Storsjo | int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, |
1054 | c8965800 | Ronald S. Bultje | int lower_transport, const char *real_challenge) |
1055 | 1617ad97 | Fabrice Bellard | { |
1056 | RTSPState *rt = s->priv_data; |
||
1057 | f830c9a4 | Ronald S. Bultje | int rtx, j, i, err, interleave = 0; |
1058 | 1617ad97 | Fabrice Bellard | RTSPStream *rtsp_st; |
1059 | a9e534d5 | Ronald S. Bultje | RTSPMessageHeader reply1, *reply = &reply1; |
1060 | 53620bba | Ronald S. Bultje | char cmd[2048]; |
1061 | e9dea59f | Ronald S. Bultje | const char *trans_pref; |
1062 | |||
1063 | 119b4668 | Ronald S. Bultje | if (rt->transport == RTSP_TRANSPORT_RDT)
|
1064 | e9dea59f | Ronald S. Bultje | trans_pref = "x-pn-tng";
|
1065 | else
|
||
1066 | trans_pref = "RTP/AVP";
|
||
1067 | 115329f1 | Diego Biurrun | |
1068 | 30e79845 | Ronald S. Bultje | /* default timeout: 1 minute */
|
1069 | rt->timeout = 60;
|
||
1070 | |||
1071 | 1617ad97 | Fabrice Bellard | /* for each stream, make the setup request */
|
1072 | /* XXX: we assume the same server is used for the control of each
|
||
1073 | c8965800 | Ronald S. Bultje | * RTSP stream */
|
1074 | d1ccf0e0 | Romain Degez | |
1075 | c8965800 | Ronald S. Bultje | for (j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) { |
1076 | 1617ad97 | Fabrice Bellard | char transport[2048]; |
1077 | |||
1078 | f830c9a4 | Ronald S. Bultje | /**
|
1079 | * WMS serves all UDP data over a single connection, the RTX, which
|
||
1080 | * isn't necessarily the first in the SDP but has to be the first
|
||
1081 | * to be set up, else the second/third SETUP will fail with a 461.
|
||
1082 | */
|
||
1083 | if (lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
|
||
1084 | rt->server_type == RTSP_SERVER_WMS) { |
||
1085 | if (i == 0) { |
||
1086 | /* rtx first */
|
||
1087 | for (rtx = 0; rtx < rt->nb_rtsp_streams; rtx++) { |
||
1088 | int len = strlen(rt->rtsp_streams[rtx]->control_url);
|
||
1089 | if (len >= 4 && |
||
1090 | c8965800 | Ronald S. Bultje | !strcmp(rt->rtsp_streams[rtx]->control_url + len - 4,
|
1091 | "/rtx"))
|
||
1092 | f830c9a4 | Ronald S. Bultje | break;
|
1093 | } |
||
1094 | if (rtx == rt->nb_rtsp_streams)
|
||
1095 | return -1; /* no RTX found */ |
||
1096 | rtsp_st = rt->rtsp_streams[rtx]; |
||
1097 | } else
|
||
1098 | rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1];
|
||
1099 | } else
|
||
1100 | 2fea9650 | Ronald S. Bultje | rtsp_st = rt->rtsp_streams[i]; |
1101 | 1617ad97 | Fabrice Bellard | |
1102 | /* RTP/UDP */
|
||
1103 | 90abbdba | Ronald S. Bultje | if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) {
|
1104 | 85fb7b34 | Fabrice Bellard | char buf[256]; |
1105 | |||
1106 | f830c9a4 | Ronald S. Bultje | if (rt->server_type == RTSP_SERVER_WMS && i > 1) { |
1107 | port = reply->transports[0].client_port_min;
|
||
1108 | goto have_port;
|
||
1109 | } |
||
1110 | |||
1111 | 85fb7b34 | Fabrice Bellard | /* first try in specified port range */
|
1112 | d1ccf0e0 | Romain Degez | if (RTSP_RTP_PORT_MIN != 0) { |
1113 | c8965800 | Ronald S. Bultje | while (j <= RTSP_RTP_PORT_MAX) {
|
1114 | 57b5555c | Martin Storsjö | ff_url_join(buf, sizeof(buf), "rtp", NULL, host, -1, |
1115 | "?localport=%d", j);
|
||
1116 | c8965800 | Ronald S. Bultje | /* we will use two ports per rtp stream (rtp and rtcp) */
|
1117 | j += 2;
|
||
1118 | if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) |
||
1119 | 85fb7b34 | Fabrice Bellard | goto rtp_opened;
|
1120 | } |
||
1121 | 1617ad97 | Fabrice Bellard | } |
1122 | 85fb7b34 | Fabrice Bellard | |
1123 | c8965800 | Ronald S. Bultje | #if 0
|
1124 | /* then try on any port */
|
||
1125 | if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) {
|
||
1126 | err = AVERROR_INVALIDDATA;
|
||
1127 | goto fail;
|
||
1128 | }
|
||
1129 | a3b058b7 | Martin Storsjö | #else
|
1130 | av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n");
|
||
1131 | err = AVERROR(EIO); |
||
1132 | goto fail;
|
||
1133 | c8965800 | Ronald S. Bultje | #endif
|
1134 | 85fb7b34 | Fabrice Bellard | |
1135 | rtp_opened:
|
||
1136 | 67f34aaa | Aurelien Jacobs | port = rtp_get_local_rtp_port(rtsp_st->rtp_handle); |
1137 | f830c9a4 | Ronald S. Bultje | have_port:
|
1138 | 0ad306bc | Ronald S. Bultje | snprintf(transport, sizeof(transport) - 1, |
1139 | eee2cbff | Ronald S. Bultje | "%s/UDP;", trans_pref);
|
1140 | if (rt->server_type != RTSP_SERVER_REAL)
|
||
1141 | av_strlcat(transport, "unicast;", sizeof(transport)); |
||
1142 | av_strlcatf(transport, sizeof(transport),
|
||
1143 | "client_port=%d", port);
|
||
1144 | f830c9a4 | Ronald S. Bultje | if (rt->transport == RTSP_TRANSPORT_RTP &&
|
1145 | !(rt->server_type == RTSP_SERVER_WMS && i > 0))
|
||
1146 | e9dea59f | Ronald S. Bultje | av_strlcatf(transport, sizeof(transport), "-%d", port + 1); |
1147 | 1617ad97 | Fabrice Bellard | } |
1148 | |||
1149 | /* RTP/TCP */
|
||
1150 | 90abbdba | Ronald S. Bultje | else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) { |
1151 | 090438cc | Ronald S. Bultje | /** For WMS streams, the application streams are only used for
|
1152 | * UDP. When trying to set it up for TCP streams, the server
|
||
1153 | * will return an error. Therefore, we skip those streams. */
|
||
1154 | if (rt->server_type == RTSP_SERVER_WMS &&
|
||
1155 | c8965800 | Ronald S. Bultje | s->streams[rtsp_st->stream_index]->codec->codec_type == |
1156 | 72415b2a | Stefano Sabatini | AVMEDIA_TYPE_DATA) |
1157 | 090438cc | Ronald S. Bultje | continue;
|
1158 | 0ad306bc | Ronald S. Bultje | snprintf(transport, sizeof(transport) - 1, |
1159 | d1c6e47c | Ronald S. Bultje | "%s/TCP;", trans_pref);
|
1160 | 895678f8 | Martin Storsjö | if (rt->transport != RTSP_TRANSPORT_RDT)
|
1161 | d1c6e47c | Ronald S. Bultje | av_strlcat(transport, "unicast;", sizeof(transport)); |
1162 | av_strlcatf(transport, sizeof(transport),
|
||
1163 | "interleaved=%d-%d",
|
||
1164 | interleave, interleave + 1);
|
||
1165 | interleave += 2;
|
||
1166 | 1617ad97 | Fabrice Bellard | } |
1167 | |||
1168 | 90abbdba | Ronald S. Bultje | else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) { |
1169 | 0ad306bc | Ronald S. Bultje | snprintf(transport, sizeof(transport) - 1, |
1170 | e9dea59f | Ronald S. Bultje | "%s/UDP;multicast", trans_pref);
|
1171 | 1617ad97 | Fabrice Bellard | } |
1172 | 69adcc4f | Martin Storsjö | if (s->oformat) {
|
1173 | av_strlcat(transport, ";mode=receive", sizeof(transport)); |
||
1174 | } else if (rt->server_type == RTSP_SERVER_REAL || |
||
1175 | 2efc97c2 | Martin Storsjö | rt->server_type == RTSP_SERVER_WMS) |
1176 | e9dea59f | Ronald S. Bultje | av_strlcat(transport, ";mode=play", sizeof(transport)); |
1177 | 115329f1 | Diego Biurrun | snprintf(cmd, sizeof(cmd),
|
1178 | b6892136 | Fabrice Bellard | "Transport: %s\r\n",
|
1179 | b17d11c6 | Martin Storsjö | transport); |
1180 | 44b70ce5 | Martin Storsjö | if (i == 0 && rt->server_type == RTSP_SERVER_REAL && CONFIG_RTPDEC) { |
1181 | e9dea59f | Ronald S. Bultje | char real_res[41], real_csum[9]; |
1182 | ff_rdt_calc_response_and_checksum(real_res, real_csum, |
||
1183 | real_challenge); |
||
1184 | av_strlcatf(cmd, sizeof(cmd),
|
||
1185 | "If-Match: %s\r\n"
|
||
1186 | "RealChallenge2: %s, sd=%s\r\n",
|
||
1187 | rt->session_id, real_res, real_csum); |
||
1188 | } |
||
1189 | b17d11c6 | Martin Storsjö | ff_rtsp_send_cmd(s, "SETUP", rtsp_st->control_url, cmd, reply, NULL); |
1190 | 8a8754d8 | Ronald S. Bultje | if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { |
1191 | err = 1;
|
||
1192 | goto fail;
|
||
1193 | 7e6ca34f | Ronald S. Bultje | } else if (reply->status_code != RTSP_STATUS_OK || |
1194 | reply->nb_transports != 1) {
|
||
1195 | 1617ad97 | Fabrice Bellard | err = AVERROR_INVALIDDATA; |
1196 | goto fail;
|
||
1197 | } |
||
1198 | |||
1199 | /* XXX: same protocol for all streams is required */
|
||
1200 | if (i > 0) { |
||
1201 | 119b4668 | Ronald S. Bultje | if (reply->transports[0].lower_transport != rt->lower_transport || |
1202 | reply->transports[0].transport != rt->transport) {
|
||
1203 | 1617ad97 | Fabrice Bellard | err = AVERROR_INVALIDDATA; |
1204 | goto fail;
|
||
1205 | } |
||
1206 | } else {
|
||
1207 | 90abbdba | Ronald S. Bultje | rt->lower_transport = reply->transports[0].lower_transport;
|
1208 | 119b4668 | Ronald S. Bultje | rt->transport = reply->transports[0].transport;
|
1209 | 1617ad97 | Fabrice Bellard | } |
1210 | |||
1211 | 8c579c1c | Martin Storsjö | /* Fail if the server responded with another lower transport mode
|
1212 | * than what we requested. */
|
||
1213 | if (reply->transports[0].lower_transport != lower_transport) { |
||
1214 | av_log(s, AV_LOG_ERROR, "Nonmatching transport in server reply\n");
|
||
1215 | err = AVERROR_INVALIDDATA; |
||
1216 | goto fail;
|
||
1217 | 1617ad97 | Fabrice Bellard | } |
1218 | |||
1219 | 90abbdba | Ronald S. Bultje | switch(reply->transports[0].lower_transport) { |
1220 | case RTSP_LOWER_TRANSPORT_TCP:
|
||
1221 | 1617ad97 | Fabrice Bellard | rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
|
1222 | rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
|
||
1223 | break;
|
||
1224 | 115329f1 | Diego Biurrun | |
1225 | c8965800 | Ronald S. Bultje | case RTSP_LOWER_TRANSPORT_UDP: {
|
1226 | a92c30d7 | Martin Storsjö | char url[1024], options[30] = ""; |
1227 | c8965800 | Ronald S. Bultje | |
1228 | a92c30d7 | Martin Storsjö | if (rt->filter_source)
|
1229 | av_strlcpy(options, "?connect=1", sizeof(options)); |
||
1230 | 619298a8 | John Wimer | /* Use source address if specified */
|
1231 | if (reply->transports[0].source[0]) { |
||
1232 | ff_url_join(url, sizeof(url), "rtp", NULL, |
||
1233 | reply->transports[0].source,
|
||
1234 | a92c30d7 | Martin Storsjö | reply->transports[0].server_port_min, options);
|
1235 | 619298a8 | John Wimer | } else {
|
1236 | 7bac991f | Ronald S. Bultje | ff_url_join(url, sizeof(url), "rtp", NULL, host, |
1237 | a92c30d7 | Martin Storsjö | reply->transports[0].server_port_min, options);
|
1238 | 619298a8 | John Wimer | } |
1239 | c8965800 | Ronald S. Bultje | if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && |
1240 | rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
|
||
1241 | err = AVERROR_INVALIDDATA; |
||
1242 | goto fail;
|
||
1243 | 1617ad97 | Fabrice Bellard | } |
1244 | 9c8fa20d | Martin Storsjö | /* Try to initialize the connection state in a
|
1245 | * potential NAT router by sending dummy packets.
|
||
1246 | * RTP/RTCP dummy packets are used for RDT, too.
|
||
1247 | */
|
||
1248 | 44b70ce5 | Martin Storsjö | if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && s->iformat && |
1249 | CONFIG_RTPDEC) |
||
1250 | 9c8fa20d | Martin Storsjö | rtp_send_punch_packets(rtsp_st->rtp_handle); |
1251 | 1617ad97 | Fabrice Bellard | break;
|
1252 | c8965800 | Ronald S. Bultje | } |
1253 | case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {
|
||
1254 | 7934b15d | Martin Storsjö | char url[1024], namebuf[50]; |
1255 | struct sockaddr_storage addr;
|
||
1256 | c8965800 | Ronald S. Bultje | int port, ttl;
|
1257 | |||
1258 | 7934b15d | Martin Storsjö | if (reply->transports[0].destination.ss_family) { |
1259 | addr = reply->transports[0].destination;
|
||
1260 | c8965800 | Ronald S. Bultje | port = reply->transports[0].port_min;
|
1261 | ttl = reply->transports[0].ttl;
|
||
1262 | } else {
|
||
1263 | 7934b15d | Martin Storsjö | addr = rtsp_st->sdp_ip; |
1264 | c8965800 | Ronald S. Bultje | port = rtsp_st->sdp_port; |
1265 | ttl = rtsp_st->sdp_ttl; |
||
1266 | } |
||
1267 | 7934b15d | Martin Storsjö | getnameinfo((struct sockaddr*) &addr, sizeof(addr), |
1268 | namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); |
||
1269 | ff_url_join(url, sizeof(url), "rtp", NULL, namebuf, |
||
1270 | 57b5555c | Martin Storsjö | port, "?ttl=%d", ttl);
|
1271 | c8965800 | Ronald S. Bultje | if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { |
1272 | err = AVERROR_INVALIDDATA; |
||
1273 | goto fail;
|
||
1274 | 1617ad97 | Fabrice Bellard | } |
1275 | break;
|
||
1276 | } |
||
1277 | c8965800 | Ronald S. Bultje | } |
1278 | d1ccf0e0 | Romain Degez | |
1279 | ee0cb67f | Ronald S. Bultje | if ((err = rtsp_open_transport_ctx(s, rtsp_st)))
|
1280 | 8b1ab7bf | Fabrice Bellard | goto fail;
|
1281 | 1617ad97 | Fabrice Bellard | } |
1282 | |||
1283 | 30e79845 | Ronald S. Bultje | if (reply->timeout > 0) |
1284 | rt->timeout = reply->timeout; |
||
1285 | |||
1286 | 2e889ae4 | Ronald S. Bultje | if (rt->server_type == RTSP_SERVER_REAL)
|
1287 | 1256d16b | Ronald S. Bultje | rt->need_subscription = 1;
|
1288 | |||
1289 | 53620bba | Ronald S. Bultje | return 0; |
1290 | |||
1291 | fail:
|
||
1292 | aeb2de1c | Martin Storsjo | ff_rtsp_undo_setup(s); |
1293 | 53620bba | Ronald S. Bultje | return err;
|
1294 | } |
||
1295 | |||
1296 | b8c2c41d | Josh Allmann | void ff_rtsp_close_connections(AVFormatContext *s)
|
1297 | { |
||
1298 | RTSPState *rt = s->priv_data; |
||
1299 | if (rt->rtsp_hd_out != rt->rtsp_hd) url_close(rt->rtsp_hd_out);
|
||
1300 | url_close(rt->rtsp_hd); |
||
1301 | 6217b645 | Martin Storsjö | rt->rtsp_hd = rt->rtsp_hd_out = NULL;
|
1302 | b8c2c41d | Josh Allmann | } |
1303 | |||
1304 | 3307e6ea | Ronald S. Bultje | int ff_rtsp_connect(AVFormatContext *s)
|
1305 | 53620bba | Ronald S. Bultje | { |
1306 | RTSPState *rt = s->priv_data; |
||
1307 | 921da217 | Luca Barbato | char host[1024], path[1024], tcpname[1024], cmd[2048], auth[128]; |
1308 | char *option_list, *option, *filename;
|
||
1309 | 03f8fc08 | Martin Storsjö | int port, err, tcp_fd;
|
1310 | 354b7573 | Axel Holzinger | RTSPMessageHeader reply1 = {0}, *reply = &reply1;
|
1311 | 90abbdba | Ronald S. Bultje | int lower_transport_mask = 0; |
1312 | 2762a7a2 | Martin Storsjö | char real_challenge[64] = ""; |
1313 | 03f8fc08 | Martin Storsjö | struct sockaddr_storage peer;
|
1314 | socklen_t peer_len = sizeof(peer);
|
||
1315 | 57b5555c | Martin Storsjö | |
1316 | if (!ff_network_init())
|
||
1317 | return AVERROR(EIO);
|
||
1318 | c8965800 | Ronald S. Bultje | redirect:
|
1319 | f5d33f52 | Josh Allmann | rt->control_transport = RTSP_MODE_PLAIN; |
1320 | 53620bba | Ronald S. Bultje | /* extract hostname and port */
|
1321 | f3bfe388 | Måns Rullgård | av_url_split(NULL, 0, auth, sizeof(auth), |
1322 | f984dcf6 | Martin Storsjö | host, sizeof(host), &port, path, sizeof(path), s->filename); |
1323 | f9337897 | Ronald S. Bultje | if (*auth) {
|
1324 | aa8bf2fb | Martin Storsjö | av_strlcpy(rt->auth, auth, sizeof(rt->auth));
|
1325 | f9337897 | Ronald S. Bultje | } |
1326 | 53620bba | Ronald S. Bultje | if (port < 0) |
1327 | port = RTSP_DEFAULT_PORT; |
||
1328 | |||
1329 | /* search for options */
|
||
1330 | 602eb779 | Martin Storsjö | option_list = strrchr(path, '?');
|
1331 | 53620bba | Ronald S. Bultje | if (option_list) {
|
1332 | 2a21adf9 | Martin Storsjö | /* Strip out the RTSP specific options, write out the rest of
|
1333 | * the options back into the same string. */
|
||
1334 | filename = option_list; |
||
1335 | c8965800 | Ronald S. Bultje | while (option_list) {
|
1336 | 53620bba | Ronald S. Bultje | /* move the option pointer */
|
1337 | 921da217 | Luca Barbato | option = ++option_list; |
1338 | 53620bba | Ronald S. Bultje | option_list = strchr(option_list, '&');
|
1339 | if (option_list)
|
||
1340 | 921da217 | Luca Barbato | *option_list = 0;
|
1341 | |||
1342 | 53620bba | Ronald S. Bultje | /* handle the options */
|
1343 | c8965800 | Ronald S. Bultje | if (!strcmp(option, "udp")) { |
1344 | 7a033e08 | Martin Storsjö | lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP);
|
1345 | c8965800 | Ronald S. Bultje | } else if (!strcmp(option, "multicast")) { |
1346 | 7a033e08 | Martin Storsjö | lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
|
1347 | c8965800 | Ronald S. Bultje | } else if (!strcmp(option, "tcp")) { |
1348 | 7a033e08 | Martin Storsjö | lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
|
1349 | f5d33f52 | Josh Allmann | } else if(!strcmp(option, "http")) { |
1350 | lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP);
|
||
1351 | rt->control_transport = RTSP_MODE_TUNNEL; |
||
1352 | a92c30d7 | Martin Storsjö | } else if (!strcmp(option, "filter_src")) { |
1353 | rt->filter_source = 1;
|
||
1354 | c8965800 | Ronald S. Bultje | } else {
|
1355 | 2a21adf9 | Martin Storsjö | /* Write options back into the buffer, using memmove instead
|
1356 | * of strcpy since the strings may overlap. */
|
||
1357 | int len = strlen(option);
|
||
1358 | memmove(++filename, option, len); |
||
1359 | filename += len; |
||
1360 | 921da217 | Luca Barbato | if (option_list) *filename = '&'; |
1361 | } |
||
1362 | 53620bba | Ronald S. Bultje | } |
1363 | 921da217 | Luca Barbato | *filename = 0;
|
1364 | 53620bba | Ronald S. Bultje | } |
1365 | |||
1366 | 90abbdba | Ronald S. Bultje | if (!lower_transport_mask)
|
1367 | 2a1d51c5 | Ronald S. Bultje | lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1; |
1368 | 53620bba | Ronald S. Bultje | |
1369 | 3e24c770 | Martin Storsjö | if (s->oformat) {
|
1370 | b7dc88fc | Martin Storsjö | /* Only UDP or TCP - UDP multicast isn't supported. */
|
1371 | lower_transport_mask &= (1 << RTSP_LOWER_TRANSPORT_UDP) |
|
||
1372 | (1 << RTSP_LOWER_TRANSPORT_TCP);
|
||
1373 | f5d33f52 | Josh Allmann | if (!lower_transport_mask || rt->control_transport == RTSP_MODE_TUNNEL) {
|
1374 | 3e24c770 | Martin Storsjö | av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, "
|
1375 | b7dc88fc | Martin Storsjö | "only UDP and TCP are supported for output.\n");
|
1376 | 3e24c770 | Martin Storsjö | err = AVERROR(EINVAL); |
1377 | goto fail;
|
||
1378 | } |
||
1379 | } |
||
1380 | |||
1381 | 4bc5cc23 | Martin Storsjö | /* Construct the URI used in request; this is similar to s->filename,
|
1382 | * but with authentication credentials removed and RTSP specific options
|
||
1383 | * stripped out. */
|
||
1384 | ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL, |
||
1385 | host, port, "%s", path);
|
||
1386 | |||
1387 | f5d33f52 | Josh Allmann | if (rt->control_transport == RTSP_MODE_TUNNEL) {
|
1388 | /* set up initial handshake for tunneling */
|
||
1389 | char httpname[1024]; |
||
1390 | char sessioncookie[17]; |
||
1391 | char headers[1024]; |
||
1392 | |||
1393 | 10ed37b5 | Martin Storsjö | ff_url_join(httpname, sizeof(httpname), "http", auth, host, port, "%s", path); |
1394 | f5d33f52 | Josh Allmann | snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x", |
1395 | av_get_random_seed(), av_get_random_seed()); |
||
1396 | |||
1397 | /* GET requests */
|
||
1398 | 9290f15d | Martin Storsjö | if (url_alloc(&rt->rtsp_hd, httpname, URL_RDONLY) < 0) { |
1399 | f5d33f52 | Josh Allmann | err = AVERROR(EIO); |
1400 | goto fail;
|
||
1401 | } |
||
1402 | |||
1403 | /* generate GET headers */
|
||
1404 | snprintf(headers, sizeof(headers),
|
||
1405 | "x-sessioncookie: %s\r\n"
|
||
1406 | "Accept: application/x-rtsp-tunnelled\r\n"
|
||
1407 | "Pragma: no-cache\r\n"
|
||
1408 | "Cache-Control: no-cache\r\n",
|
||
1409 | sessioncookie); |
||
1410 | 00e4a1f4 | Josh Allmann | ff_http_set_headers(rt->rtsp_hd, headers); |
1411 | f5d33f52 | Josh Allmann | |
1412 | /* complete the connection */
|
||
1413 | 9290f15d | Martin Storsjö | if (url_connect(rt->rtsp_hd)) {
|
1414 | f5d33f52 | Josh Allmann | err = AVERROR(EIO); |
1415 | goto fail;
|
||
1416 | } |
||
1417 | |||
1418 | /* POST requests */
|
||
1419 | 9290f15d | Martin Storsjö | if (url_alloc(&rt->rtsp_hd_out, httpname, URL_WRONLY) < 0 ) { |
1420 | f5d33f52 | Josh Allmann | err = AVERROR(EIO); |
1421 | goto fail;
|
||
1422 | } |
||
1423 | |||
1424 | /* generate POST headers */
|
||
1425 | snprintf(headers, sizeof(headers),
|
||
1426 | "x-sessioncookie: %s\r\n"
|
||
1427 | "Content-Type: application/x-rtsp-tunnelled\r\n"
|
||
1428 | "Pragma: no-cache\r\n"
|
||
1429 | "Cache-Control: no-cache\r\n"
|
||
1430 | "Content-Length: 32767\r\n"
|
||
1431 | "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n",
|
||
1432 | sessioncookie); |
||
1433 | 00e4a1f4 | Josh Allmann | ff_http_set_headers(rt->rtsp_hd_out, headers); |
1434 | ff_http_set_chunked_transfer_encoding(rt->rtsp_hd_out, 0);
|
||
1435 | f5d33f52 | Josh Allmann | |
1436 | a8ead332 | Martin Storsjö | /* Initialize the authentication state for the POST session. The HTTP
|
1437 | * protocol implementation doesn't properly handle multi-pass
|
||
1438 | * authentication for POST requests, since it would require one of
|
||
1439 | * the following:
|
||
1440 | * - implementing Expect: 100-continue, which many HTTP servers
|
||
1441 | * don't support anyway, even less the RTSP servers that do HTTP
|
||
1442 | * tunneling
|
||
1443 | * - sending the whole POST data until getting a 401 reply specifying
|
||
1444 | * what authentication method to use, then resending all that data
|
||
1445 | * - waiting for potential 401 replies directly after sending the
|
||
1446 | * POST header (waiting for some unspecified time)
|
||
1447 | * Therefore, we copy the full auth state, which works for both basic
|
||
1448 | * and digest. (For digest, we would have to synchronize the nonce
|
||
1449 | * count variable between the two sessions, if we'd do more requests
|
||
1450 | * with the original session, though.)
|
||
1451 | */
|
||
1452 | ff_http_init_auth_state(rt->rtsp_hd_out, rt->rtsp_hd); |
||
1453 | |||
1454 | 9290f15d | Martin Storsjö | /* complete the connection */
|
1455 | if (url_connect(rt->rtsp_hd_out)) {
|
||
1456 | err = AVERROR(EIO); |
||
1457 | goto fail;
|
||
1458 | } |
||
1459 | f5d33f52 | Josh Allmann | } else {
|
1460 | 48e77473 | Martin Storsjö | /* open the tcp connection */
|
1461 | 41874d0a | Josh Allmann | ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL); |
1462 | 00e4a1f4 | Josh Allmann | if (url_open(&rt->rtsp_hd, tcpname, URL_RDWR) < 0) { |
1463 | 41874d0a | Josh Allmann | err = AVERROR(EIO); |
1464 | goto fail;
|
||
1465 | } |
||
1466 | 00e4a1f4 | Josh Allmann | rt->rtsp_hd_out = rt->rtsp_hd; |
1467 | f5d33f52 | Josh Allmann | } |
1468 | 53620bba | Ronald S. Bultje | rt->seq = 0;
|
1469 | |||
1470 | 00e4a1f4 | Josh Allmann | tcp_fd = url_get_file_handle(rt->rtsp_hd); |
1471 | 03f8fc08 | Martin Storsjö | if (!getpeername(tcp_fd, (struct sockaddr*) &peer, &peer_len)) { |
1472 | getnameinfo((struct sockaddr*) &peer, peer_len, host, sizeof(host), |
||
1473 | NULL, 0, NI_NUMERICHOST); |
||
1474 | } |
||
1475 | |||
1476 | c8965800 | Ronald S. Bultje | /* request options supported by the server; this also detects server
|
1477 | * type */
|
||
1478 | 1cf151e9 | Ronald S. Bultje | for (rt->server_type = RTSP_SERVER_RTP;;) {
|
1479 | b17d11c6 | Martin Storsjö | cmd[0] = 0; |
1480 | 2e889ae4 | Ronald S. Bultje | if (rt->server_type == RTSP_SERVER_REAL)
|
1481 | 1cf151e9 | Ronald S. Bultje | av_strlcat(cmd, |
1482 | /**
|
||
1483 | * The following entries are required for proper
|
||
1484 | * streaming from a Realmedia server. They are
|
||
1485 | * interdependent in some way although we currently
|
||
1486 | * don't quite understand how. Values were copied
|
||
1487 | * from mplayer SVN r23589.
|
||
1488 | * @param CompanyID is a 16-byte ID in base64
|
||
1489 | * @param ClientChallenge is a 16-byte ID in hex
|
||
1490 | */
|
||
1491 | "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n"
|
||
1492 | "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n"
|
||
1493 | "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n"
|
||
1494 | "GUID: 00000000-0000-0000-0000-000000000000\r\n",
|
||
1495 | sizeof(cmd));
|
||
1496 | b17d11c6 | Martin Storsjö | ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL); |
1497 | 1cf151e9 | Ronald S. Bultje | if (reply->status_code != RTSP_STATUS_OK) {
|
1498 | err = AVERROR_INVALIDDATA; |
||
1499 | goto fail;
|
||
1500 | } |
||
1501 | |||
1502 | /* detect server type if not standard-compliant RTP */
|
||
1503 | 2e889ae4 | Ronald S. Bultje | if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { |
1504 | rt->server_type = RTSP_SERVER_REAL; |
||
1505 | 1cf151e9 | Ronald S. Bultje | continue;
|
1506 | 7a86bafa | Ronald S. Bultje | } else if (!strncasecmp(reply->server, "WMServer/", 9)) { |
1507 | rt->server_type = RTSP_SERVER_WMS; |
||
1508 | c8965800 | Ronald S. Bultje | } else if (rt->server_type == RTSP_SERVER_REAL) |
1509 | 1cf151e9 | Ronald S. Bultje | strcpy(real_challenge, reply->real_challenge); |
1510 | break;
|
||
1511 | } |
||
1512 | |||
1513 | 44b70ce5 | Martin Storsjö | if (s->iformat && CONFIG_RTSP_DEMUXER)
|
1514 | 0526c6f7 | Martin Storsjö | err = ff_rtsp_setup_input_streams(s, reply); |
1515 | 44b70ce5 | Martin Storsjö | else if (CONFIG_RTSP_MUXER) |
1516 | c2688f3a | Martin Storsjö | err = ff_rtsp_setup_output_streams(s, host); |
1517 | e23d195d | Martin Storsjö | if (err)
|
1518 | 53620bba | Ronald S. Bultje | goto fail;
|
1519 | |||
1520 | 8a8754d8 | Ronald S. Bultje | do {
|
1521 | c8965800 | Ronald S. Bultje | int lower_transport = ff_log2_tab[lower_transport_mask &
|
1522 | ~(lower_transport_mask - 1)];
|
||
1523 | 8a8754d8 | Ronald S. Bultje | |
1524 | fef5649a | Martin Storsjo | err = ff_rtsp_make_setup_request(s, host, port, lower_transport, |
1525 | 2e889ae4 | Ronald S. Bultje | rt->server_type == RTSP_SERVER_REAL ? |
1526 | e9dea59f | Ronald S. Bultje | real_challenge : NULL);
|
1527 | 8a8754d8 | Ronald S. Bultje | if (err < 0) |
1528 | 7e6ca34f | Ronald S. Bultje | goto fail;
|
1529 | 90abbdba | Ronald S. Bultje | lower_transport_mask &= ~(1 << lower_transport);
|
1530 | if (lower_transport_mask == 0 && err == 1) { |
||
1531 | 28c4741a | Martin Storsjö | err = AVERROR(EPROTONOSUPPORT); |
1532 | 8a8754d8 | Ronald S. Bultje | goto fail;
|
1533 | } |
||
1534 | } while (err);
|
||
1535 | 53620bba | Ronald S. Bultje | |
1536 | 2762a7a2 | Martin Storsjö | rt->lower_transport_mask = lower_transport_mask; |
1537 | av_strlcpy(rt->real_challenge, real_challenge, sizeof(rt->real_challenge));
|
||
1538 | ff762d6e | Fabrice Bellard | rt->state = RTSP_STATE_IDLE; |
1539 | c8965800 | Ronald S. Bultje | rt->seek_timestamp = 0; /* default is to start stream at position zero */ |
1540 | 1617ad97 | Fabrice Bellard | return 0; |
1541 | fail:
|
||
1542 | 3307e6ea | Ronald S. Bultje | ff_rtsp_close_streams(s); |
1543 | b8c2c41d | Josh Allmann | ff_rtsp_close_connections(s); |
1544 | 35cfd646 | Martin Storsjö | if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) { |
1545 | d243ba30 | Luca Barbato | av_strlcpy(s->filename, reply->location, sizeof(s->filename));
|
1546 | av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n",
|
||
1547 | reply->status_code, |
||
1548 | s->filename); |
||
1549 | goto redirect;
|
||
1550 | } |
||
1551 | 57b5555c | Martin Storsjö | ff_network_close(); |
1552 | 1617ad97 | Fabrice Bellard | return err;
|
1553 | } |
||
1554 | 2e802e38 | Diego Biurrun | #endif /* CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER */ |
1555 | 1617ad97 | Fabrice Bellard | |
1556 | 44b70ce5 | Martin Storsjö | #if CONFIG_RTPDEC
|
1557 | 0e59034e | Ronald S. Bultje | static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, |
1558 | 321259c1 | Martin Storsjö | uint8_t *buf, int buf_size, int64_t wait_end)
|
1559 | 0e59034e | Ronald S. Bultje | { |
1560 | RTSPState *rt = s->priv_data; |
||
1561 | RTSPStream *rtsp_st; |
||
1562 | a8475bbd | Luca Barbato | int n, i, ret, tcp_fd, timeout_cnt = 0; |
1563 | int max_p = 0; |
||
1564 | struct pollfd *p = rt->p;
|
||
1565 | 0e59034e | Ronald S. Bultje | |
1566 | c8965800 | Ronald S. Bultje | for (;;) {
|
1567 | 0e59034e | Ronald S. Bultje | if (url_interrupt_cb())
|
1568 | c76374c6 | Nicolas George | return AVERROR_EXIT;
|
1569 | 321259c1 | Martin Storsjö | if (wait_end && wait_end - av_gettime() < 0) |
1570 | return AVERROR(EAGAIN);
|
||
1571 | a8475bbd | Luca Barbato | max_p = 0;
|
1572 | 0e59034e | Ronald S. Bultje | if (rt->rtsp_hd) {
|
1573 | a8475bbd | Luca Barbato | tcp_fd = url_get_file_handle(rt->rtsp_hd); |
1574 | p[max_p].fd = tcp_fd; |
||
1575 | p[max_p++].events = POLLIN; |
||
1576 | 0e59034e | Ronald S. Bultje | } else {
|
1577 | tcp_fd = -1;
|
||
1578 | } |
||
1579 | c8965800 | Ronald S. Bultje | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
1580 | 0e59034e | Ronald S. Bultje | rtsp_st = rt->rtsp_streams[i]; |
1581 | if (rtsp_st->rtp_handle) {
|
||
1582 | a8475bbd | Luca Barbato | p[max_p].fd = url_get_file_handle(rtsp_st->rtp_handle); |
1583 | p[max_p++].events = POLLIN; |
||
1584 | p[max_p].fd = rtp_get_rtcp_file_handle(rtsp_st->rtp_handle); |
||
1585 | p[max_p++].events = POLLIN; |
||
1586 | 0e59034e | Ronald S. Bultje | } |
1587 | } |
||
1588 | a8475bbd | Luca Barbato | n = poll(p, max_p, POLL_TIMEOUT_MS); |
1589 | 0e59034e | Ronald S. Bultje | if (n > 0) { |
1590 | a8475bbd | Luca Barbato | int j = 1 - (tcp_fd == -1); |
1591 | 9cba6f5f | Sam Gerstein | timeout_cnt = 0;
|
1592 | c8965800 | Ronald S. Bultje | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
1593 | 0e59034e | Ronald S. Bultje | rtsp_st = rt->rtsp_streams[i]; |
1594 | if (rtsp_st->rtp_handle) {
|
||
1595 | a8475bbd | Luca Barbato | if (p[j].revents & POLLIN || p[j+1].revents & POLLIN) { |
1596 | 0e59034e | Ronald S. Bultje | ret = url_read(rtsp_st->rtp_handle, buf, buf_size); |
1597 | if (ret > 0) { |
||
1598 | *prtsp_st = rtsp_st; |
||
1599 | return ret;
|
||
1600 | } |
||
1601 | } |
||
1602 | a8475bbd | Luca Barbato | j+=2;
|
1603 | 0e59034e | Ronald S. Bultje | } |
1604 | } |
||
1605 | 5fe8021a | Martin Storsjö | #if CONFIG_RTSP_DEMUXER
|
1606 | a8475bbd | Luca Barbato | if (tcp_fd != -1 && p[0].revents & POLLIN) { |
1607 | 0e59034e | Ronald S. Bultje | RTSPMessageHeader reply; |
1608 | |||
1609 | 3df54c6b | Martin Storsjö | ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL); |
1610 | 3032276b | Martin Storsjö | if (ret < 0) |
1611 | return ret;
|
||
1612 | 0e59034e | Ronald S. Bultje | /* XXX: parse message */
|
1613 | c02fd3d2 | Martin Storsjö | if (rt->state != RTSP_STATE_STREAMING)
|
1614 | 0e59034e | Ronald S. Bultje | return 0; |
1615 | } |
||
1616 | 5fe8021a | Martin Storsjö | #endif
|
1617 | 9cba6f5f | Sam Gerstein | } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) { |
1618 | 28c4741a | Martin Storsjö | return AVERROR(ETIMEDOUT);
|
1619 | 9cba6f5f | Sam Gerstein | } else if (n < 0 && errno != EINTR) |
1620 | return AVERROR(errno);
|
||
1621 | 0e59034e | Ronald S. Bultje | } |
1622 | } |
||
1623 | |||
1624 | 0526c6f7 | Martin Storsjö | int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
|
1625 | 0e59034e | Ronald S. Bultje | { |
1626 | RTSPState *rt = s->priv_data; |
||
1627 | int ret, len;
|
||
1628 | 321259c1 | Martin Storsjö | RTSPStream *rtsp_st, *first_queue_st = NULL;
|
1629 | int64_t wait_end = 0;
|
||
1630 | 0e59034e | Ronald S. Bultje | |
1631 | b20359f5 | Josh Allmann | if (rt->nb_byes == rt->nb_rtsp_streams)
|
1632 | return AVERROR_EOF;
|
||
1633 | |||
1634 | 0e59034e | Ronald S. Bultje | /* get next frames from the same RTP packet */
|
1635 | if (rt->cur_transport_priv) {
|
||
1636 | c8965800 | Ronald S. Bultje | if (rt->transport == RTSP_TRANSPORT_RDT) {
|
1637 | 0e59034e | Ronald S. Bultje | ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); |
1638 | c8965800 | Ronald S. Bultje | } else
|
1639 | 0e59034e | Ronald S. Bultje | ret = rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); |
1640 | if (ret == 0) { |
||
1641 | rt->cur_transport_priv = NULL;
|
||
1642 | return 0; |
||
1643 | } else if (ret == 1) { |
||
1644 | return 0; |
||
1645 | c8965800 | Ronald S. Bultje | } else
|
1646 | 0e59034e | Ronald S. Bultje | rt->cur_transport_priv = NULL;
|
1647 | } |
||
1648 | |||
1649 | 321259c1 | Martin Storsjö | if (rt->transport == RTSP_TRANSPORT_RTP) {
|
1650 | int i;
|
||
1651 | int64_t first_queue_time = 0;
|
||
1652 | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
||
1653 | RTPDemuxContext *rtpctx = rt->rtsp_streams[i]->transport_priv; |
||
1654 | 9e99f84f | Martin Storsjö | int64_t queue_time; |
1655 | if (!rtpctx)
|
||
1656 | continue;
|
||
1657 | queue_time = ff_rtp_queued_packet_time(rtpctx); |
||
1658 | 321259c1 | Martin Storsjö | if (queue_time && (queue_time - first_queue_time < 0 || |
1659 | !first_queue_time)) { |
||
1660 | first_queue_time = queue_time; |
||
1661 | first_queue_st = rt->rtsp_streams[i]; |
||
1662 | } |
||
1663 | } |
||
1664 | if (first_queue_time)
|
||
1665 | wait_end = first_queue_time + s->max_delay; |
||
1666 | } |
||
1667 | |||
1668 | 0e59034e | Ronald S. Bultje | /* read next RTP packet */
|
1669 | redo:
|
||
1670 | 96a7c975 | Martin Storsjö | if (!rt->recvbuf) {
|
1671 | rt->recvbuf = av_malloc(RECVBUF_SIZE); |
||
1672 | if (!rt->recvbuf)
|
||
1673 | return AVERROR(ENOMEM);
|
||
1674 | } |
||
1675 | |||
1676 | 0e59034e | Ronald S. Bultje | switch(rt->lower_transport) {
|
1677 | default:
|
||
1678 | 5fe8021a | Martin Storsjö | #if CONFIG_RTSP_DEMUXER
|
1679 | 0e59034e | Ronald S. Bultje | case RTSP_LOWER_TRANSPORT_TCP:
|
1680 | 0526c6f7 | Martin Storsjö | len = ff_rtsp_tcp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE); |
1681 | 0e59034e | Ronald S. Bultje | break;
|
1682 | 5fe8021a | Martin Storsjö | #endif
|
1683 | 0e59034e | Ronald S. Bultje | case RTSP_LOWER_TRANSPORT_UDP:
|
1684 | case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
|
||
1685 | 321259c1 | Martin Storsjö | len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end); |
1686 | 2c35a6bd | Martin Storsjö | if (len > 0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) |
1687 | 0e59034e | Ronald S. Bultje | rtp_check_and_send_back_rr(rtsp_st->transport_priv, len); |
1688 | break;
|
||
1689 | } |
||
1690 | 321259c1 | Martin Storsjö | if (len == AVERROR(EAGAIN) && first_queue_st &&
|
1691 | rt->transport == RTSP_TRANSPORT_RTP) { |
||
1692 | rtsp_st = first_queue_st; |
||
1693 | ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, NULL, 0); |
||
1694 | goto end;
|
||
1695 | } |
||
1696 | 0e59034e | Ronald S. Bultje | if (len < 0) |
1697 | return len;
|
||
1698 | if (len == 0) |
||
1699 | return AVERROR_EOF;
|
||
1700 | c8965800 | Ronald S. Bultje | if (rt->transport == RTSP_TRANSPORT_RDT) {
|
1701 | ad4ad27f | Martin Storsjö | ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); |
1702 | 2cab6b48 | Martin Storsjö | } else {
|
1703 | ad4ad27f | Martin Storsjö | ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); |
1704 | 2cab6b48 | Martin Storsjö | if (ret < 0) { |
1705 | /* Either bad packet, or a RTCP packet. Check if the
|
||
1706 | * first_rtcp_ntp_time field was initialized. */
|
||
1707 | RTPDemuxContext *rtpctx = rtsp_st->transport_priv; |
||
1708 | if (rtpctx->first_rtcp_ntp_time != AV_NOPTS_VALUE) {
|
||
1709 | /* first_rtcp_ntp_time has been initialized for this stream,
|
||
1710 | * copy the same value to all other uninitialized streams,
|
||
1711 | * in order to map their timestamp origin to the same ntp time
|
||
1712 | * as this one. */
|
||
1713 | int i;
|
||
1714 | 3a1cdcc7 | Martin Storsjö | AVStream *st = NULL;
|
1715 | if (rtsp_st->stream_index >= 0) |
||
1716 | st = s->streams[rtsp_st->stream_index]; |
||
1717 | 2cab6b48 | Martin Storsjö | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
1718 | 744a882f | Martin Storsjö | RTPDemuxContext *rtpctx2 = rt->rtsp_streams[i]->transport_priv; |
1719 | 3a1cdcc7 | Martin Storsjö | AVStream *st2 = NULL;
|
1720 | if (rt->rtsp_streams[i]->stream_index >= 0) |
||
1721 | st2 = s->streams[rt->rtsp_streams[i]->stream_index]; |
||
1722 | if (rtpctx2 && st && st2 &&
|
||
1723 | rtpctx2->first_rtcp_ntp_time == AV_NOPTS_VALUE) { |
||
1724 | 2cab6b48 | Martin Storsjö | rtpctx2->first_rtcp_ntp_time = rtpctx->first_rtcp_ntp_time; |
1725 | 3a1cdcc7 | Martin Storsjö | rtpctx2->rtcp_ts_offset = av_rescale_q( |
1726 | rtpctx->rtcp_ts_offset, st->time_base, |
||
1727 | st2->time_base); |
||
1728 | } |
||
1729 | 2cab6b48 | Martin Storsjö | } |
1730 | } |
||
1731 | b20359f5 | Josh Allmann | if (ret == -RTCP_BYE) {
|
1732 | rt->nb_byes++; |
||
1733 | |||
1734 | av_log(s, AV_LOG_DEBUG, "Received BYE for stream %d (%d/%d)\n",
|
||
1735 | rtsp_st->stream_index, rt->nb_byes, rt->nb_rtsp_streams); |
||
1736 | |||
1737 | if (rt->nb_byes == rt->nb_rtsp_streams)
|
||
1738 | return AVERROR_EOF;
|
||
1739 | } |
||
1740 | 2cab6b48 | Martin Storsjö | } |
1741 | } |
||
1742 | 321259c1 | Martin Storsjö | end:
|
1743 | 0e59034e | Ronald S. Bultje | if (ret < 0) |
1744 | goto redo;
|
||
1745 | c8965800 | Ronald S. Bultje | if (ret == 1) |
1746 | 0e59034e | Ronald S. Bultje | /* more packets may follow, so we save the RTP context */
|
1747 | rt->cur_transport_priv = rtsp_st->transport_priv; |
||
1748 | |||
1749 | return ret;
|
||
1750 | } |
||
1751 | 44b70ce5 | Martin Storsjö | #endif /* CONFIG_RTPDEC */ |
1752 | 0e59034e | Ronald S. Bultje | |
1753 | 44b70ce5 | Martin Storsjö | #if CONFIG_SDP_DEMUXER
|
1754 | cb1fdc61 | Fabrice Bellard | static int sdp_probe(AVProbeData *p1) |
1755 | 93ced3e8 | Fabrice Bellard | { |
1756 | 0e1ceacd | Michael Niedermayer | const char *p = p1->buf, *p_end = p1->buf + p1->buf_size; |
1757 | cb1fdc61 | Fabrice Bellard | |
1758 | 3fbd12d1 | Martin Storsjö | /* we look for a line beginning "c=IN IP" */
|
1759 | 0e1ceacd | Michael Niedermayer | while (p < p_end && *p != '\0') { |
1760 | 3fbd12d1 | Martin Storsjö | if (p + sizeof("c=IN IP") - 1 < p_end && |
1761 | av_strstart(p, "c=IN IP", NULL)) |
||
1762 | cb1fdc61 | Fabrice Bellard | return AVPROBE_SCORE_MAX / 2; |
1763 | 0e1ceacd | Michael Niedermayer | |
1764 | c8965800 | Ronald S. Bultje | while (p < p_end - 1 && *p != '\n') p++; |
1765 | 0e1ceacd | Michael Niedermayer | if (++p >= p_end)
|
1766 | cb1fdc61 | Fabrice Bellard | break;
|
1767 | if (*p == '\r') |
||
1768 | p++; |
||
1769 | } |
||
1770 | 93ced3e8 | Fabrice Bellard | return 0; |
1771 | } |
||
1772 | |||
1773 | c8965800 | Ronald S. Bultje | static int sdp_read_header(AVFormatContext *s, AVFormatParameters *ap) |
1774 | 93ced3e8 | Fabrice Bellard | { |
1775 | 8b1ab7bf | Fabrice Bellard | RTSPState *rt = s->priv_data; |
1776 | 93ced3e8 | Fabrice Bellard | RTSPStream *rtsp_st; |
1777 | int size, i, err;
|
||
1778 | char *content;
|
||
1779 | char url[1024]; |
||
1780 | |||
1781 | 57b5555c | Martin Storsjö | if (!ff_network_init())
|
1782 | return AVERROR(EIO);
|
||
1783 | |||
1784 | 93ced3e8 | Fabrice Bellard | /* read the whole sdp file */
|
1785 | /* XXX: better loading */
|
||
1786 | content = av_malloc(SDP_MAX_SIZE); |
||
1787 | b7effd4e | Anton Khirnov | size = avio_read(s->pb, content, SDP_MAX_SIZE - 1);
|
1788 | 93ced3e8 | Fabrice Bellard | if (size <= 0) { |
1789 | av_free(content); |
||
1790 | return AVERROR_INVALIDDATA;
|
||
1791 | } |
||
1792 | content[size] ='\0';
|
||
1793 | |||
1794 | f81c7ac7 | Luca Barbato | err = ff_sdp_parse(s, content); |
1795 | 93ced3e8 | Fabrice Bellard | av_free(content); |
1796 | f81c7ac7 | Luca Barbato | if (err) goto fail; |
1797 | 93ced3e8 | Fabrice Bellard | |
1798 | /* open each RTP stream */
|
||
1799 | c8965800 | Ronald S. Bultje | for (i = 0; i < rt->nb_rtsp_streams; i++) { |
1800 | 3fbd12d1 | Martin Storsjö | char namebuf[50]; |
1801 | 8b1ab7bf | Fabrice Bellard | rtsp_st = rt->rtsp_streams[i]; |
1802 | 115329f1 | Diego Biurrun | |
1803 | 3fbd12d1 | Martin Storsjö | getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip), |
1804 | namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); |
||
1805 | 57b5555c | Martin Storsjö | ff_url_join(url, sizeof(url), "rtp", NULL, |
1806 | 3fbd12d1 | Martin Storsjö | namebuf, rtsp_st->sdp_port, |
1807 | 57b5555c | Martin Storsjö | "?localport=%d&ttl=%d", rtsp_st->sdp_port,
|
1808 | rtsp_st->sdp_ttl); |
||
1809 | dbf30963 | Thijs | if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { |
1810 | 93ced3e8 | Fabrice Bellard | err = AVERROR_INVALIDDATA; |
1811 | goto fail;
|
||
1812 | } |
||
1813 | ee0cb67f | Ronald S. Bultje | if ((err = rtsp_open_transport_ctx(s, rtsp_st)))
|
1814 | 8b1ab7bf | Fabrice Bellard | goto fail;
|
1815 | 93ced3e8 | Fabrice Bellard | } |
1816 | return 0; |
||
1817 | c8965800 | Ronald S. Bultje | fail:
|
1818 | 3307e6ea | Ronald S. Bultje | ff_rtsp_close_streams(s); |
1819 | 57b5555c | Martin Storsjö | ff_network_close(); |
1820 | 93ced3e8 | Fabrice Bellard | return err;
|
1821 | } |
||
1822 | |||
1823 | static int sdp_read_close(AVFormatContext *s) |
||
1824 | { |
||
1825 | 3307e6ea | Ronald S. Bultje | ff_rtsp_close_streams(s); |
1826 | 57b5555c | Martin Storsjö | ff_network_close(); |
1827 | 93ced3e8 | Fabrice Bellard | return 0; |
1828 | } |
||
1829 | |||
1830 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_sdp_demuxer = { |
1831 | 93ced3e8 | Fabrice Bellard | "sdp",
|
1832 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("SDP"),
|
1833 | 93ced3e8 | Fabrice Bellard | sizeof(RTSPState),
|
1834 | sdp_probe, |
||
1835 | sdp_read_header, |
||
1836 | 0526c6f7 | Martin Storsjö | ff_rtsp_fetch_packet, |
1837 | 93ced3e8 | Fabrice Bellard | sdp_read_close, |
1838 | }; |
||
1839 | 44b70ce5 | Martin Storsjö | #endif /* CONFIG_SDP_DEMUXER */ |
1840 | 44594cc7 | Martin Storsjö | |
1841 | 44b70ce5 | Martin Storsjö | #if CONFIG_RTP_DEMUXER
|
1842 | 44594cc7 | Martin Storsjö | static int rtp_probe(AVProbeData *p) |
1843 | { |
||
1844 | if (av_strstart(p->filename, "rtp:", NULL)) |
||
1845 | return AVPROBE_SCORE_MAX;
|
||
1846 | return 0; |
||
1847 | } |
||
1848 | |||
1849 | static int rtp_read_header(AVFormatContext *s, |
||
1850 | AVFormatParameters *ap) |
||
1851 | { |
||
1852 | uint8_t recvbuf[1500];
|
||
1853 | char host[500], sdp[500]; |
||
1854 | int ret, port;
|
||
1855 | URLContext* in = NULL;
|
||
1856 | int payload_type;
|
||
1857 | AVCodecContext codec; |
||
1858 | struct sockaddr_storage addr;
|
||
1859 | ae628ec1 | Anton Khirnov | AVIOContext pb; |
1860 | 44594cc7 | Martin Storsjö | socklen_t addrlen = sizeof(addr);
|
1861 | |||
1862 | if (!ff_network_init())
|
||
1863 | return AVERROR(EIO);
|
||
1864 | |||
1865 | ret = url_open(&in, s->filename, URL_RDONLY); |
||
1866 | if (ret)
|
||
1867 | goto fail;
|
||
1868 | |||
1869 | while (1) { |
||
1870 | ret = url_read(in, recvbuf, sizeof(recvbuf));
|
||
1871 | if (ret == AVERROR(EAGAIN))
|
||
1872 | continue;
|
||
1873 | if (ret < 0) |
||
1874 | goto fail;
|
||
1875 | if (ret < 12) { |
||
1876 | av_log(s, AV_LOG_WARNING, "Received too short packet\n");
|
||
1877 | continue;
|
||
1878 | } |
||
1879 | |||
1880 | if ((recvbuf[0] & 0xc0) != 0x80) { |
||
1881 | av_log(s, AV_LOG_WARNING, "Unsupported RTP version packet "
|
||
1882 | "received\n");
|
||
1883 | continue;
|
||
1884 | } |
||
1885 | |||
1886 | payload_type = recvbuf[1] & 0x7f; |
||
1887 | break;
|
||
1888 | } |
||
1889 | getsockname(url_get_file_handle(in), (struct sockaddr*) &addr, &addrlen);
|
||
1890 | url_close(in); |
||
1891 | in = NULL;
|
||
1892 | |||
1893 | memset(&codec, 0, sizeof(codec)); |
||
1894 | if (ff_rtp_get_codec_info(&codec, payload_type)) {
|
||
1895 | av_log(s, AV_LOG_ERROR, "Unable to receive RTP payload type %d "
|
||
1896 | "without an SDP file describing it\n",
|
||
1897 | payload_type); |
||
1898 | goto fail;
|
||
1899 | } |
||
1900 | if (codec.codec_type != AVMEDIA_TYPE_DATA) {
|
||
1901 | av_log(s, AV_LOG_WARNING, "Guessing on RTP content - if not received "
|
||
1902 | "properly you need an SDP file "
|
||
1903 | "describing it\n");
|
||
1904 | } |
||
1905 | |||
1906 | av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, |
||
1907 | NULL, 0, s->filename); |
||
1908 | |||
1909 | snprintf(sdp, sizeof(sdp),
|
||
1910 | "v=0\r\nc=IN IP%d %s\r\nm=%s %d RTP/AVP %d\r\n",
|
||
1911 | addr.ss_family == AF_INET ? 4 : 6, host, |
||
1912 | codec.codec_type == AVMEDIA_TYPE_DATA ? "application" :
|
||
1913 | codec.codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio", |
||
1914 | port, payload_type); |
||
1915 | av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp);
|
||
1916 | |||
1917 | e731b8d8 | Anton Khirnov | ffio_init_context(&pb, sdp, strlen(sdp), 0, NULL, NULL, NULL, NULL); |
1918 | 44594cc7 | Martin Storsjö | s->pb = &pb; |
1919 | |||
1920 | /* sdp_read_header initializes this again */
|
||
1921 | ff_network_close(); |
||
1922 | |||
1923 | ret = sdp_read_header(s, ap); |
||
1924 | s->pb = NULL;
|
||
1925 | return ret;
|
||
1926 | |||
1927 | fail:
|
||
1928 | if (in)
|
||
1929 | url_close(in); |
||
1930 | ff_network_close(); |
||
1931 | return ret;
|
||
1932 | } |
||
1933 | |||
1934 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_rtp_demuxer = { |
1935 | 44594cc7 | Martin Storsjö | "rtp",
|
1936 | NULL_IF_CONFIG_SMALL("RTP input format"),
|
||
1937 | sizeof(RTSPState),
|
||
1938 | rtp_probe, |
||
1939 | rtp_read_header, |
||
1940 | 0526c6f7 | Martin Storsjö | ff_rtsp_fetch_packet, |
1941 | 44594cc7 | Martin Storsjö | sdp_read_close, |
1942 | .flags = AVFMT_NOFILE, |
||
1943 | }; |
||
1944 | 44b70ce5 | Martin Storsjö | #endif /* CONFIG_RTP_DEMUXER */ |