Mercurial > libavformat.hg
annotate rtsp.c @ 571:4a755492b90b libavformat
* Introducing IIDC1394 grabbing interface.
Use it with -grab dc1394
* Introducing yet another packed pix_fmt in order to support some of
the IIDC1394 modes: uyvy411 (Cb Y0 Y1 Cr Y2 Y3).
author | romansh |
---|---|
date | Fri, 22 Oct 2004 02:04:30 +0000 |
parents | 89bd76208427 |
children | fe24632a577b |
rev | line source |
---|---|
0 | 1 /* |
2 * RTSP/SDP client | |
3 * Copyright (c) 2002 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 #include "avformat.h" | |
20 | |
182 | 21 #include <unistd.h> /* for select() prototype */ |
0 | 22 #include <sys/time.h> |
23 #include <netinet/in.h> | |
24 #include <sys/socket.h> | |
25 #ifndef __BEOS__ | |
26 # include <arpa/inet.h> | |
27 #else | |
28 # include "barpainet.h" | |
29 #endif | |
30 | |
31 //#define DEBUG | |
172 | 32 //#define DEBUG_RTP_TCP |
0 | 33 |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
34 enum RTSPClientState { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
35 RTSP_STATE_IDLE, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
36 RTSP_STATE_PLAYING, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
37 RTSP_STATE_PAUSED, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
38 }; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
39 |
0 | 40 typedef struct RTSPState { |
41 URLContext *rtsp_hd; /* RTSP TCP connexion handle */ | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
42 int nb_rtsp_streams; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
43 struct RTSPStream **rtsp_streams; |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
44 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
45 enum RTSPClientState state; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
46 int64_t seek_timestamp; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
47 |
172 | 48 /* XXX: currently we use unbuffered input */ |
49 // ByteIOContext rtsp_gb; | |
0 | 50 int seq; /* RTSP command sequence number */ |
51 char session_id[512]; | |
52 enum RTSPProtocol protocol; | |
53 char last_reply[2048]; /* XXX: allocate ? */ | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
54 RTPDemuxContext *cur_rtp; |
0 | 55 } RTSPState; |
56 | |
57 typedef struct RTSPStream { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
58 URLContext *rtp_handle; /* RTP stream handle */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
59 RTPDemuxContext *rtp_ctx; /* RTP parse context */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
60 |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
61 int stream_index; /* corresponding stream index, if any. -1 if none (MPEG2TS case) */ |
0 | 62 int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */ |
63 char control_url[1024]; /* url for this stream (from SDP) */ | |
64 | |
65 int sdp_port; /* port (from SDP content - not used in RTSP) */ | |
66 struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */ | |
67 int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */ | |
68 int sdp_payload_type; /* payload type - only used in SDP */ | |
69 } RTSPStream; | |
70 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
71 static int rtsp_read_play(AVFormatContext *s); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
72 |
0 | 73 /* XXX: currently, the only way to change the protocols consists in |
74 changing this variable */ | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
75 #if 0 |
0 | 76 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST); |
172 | 77 #else |
78 /* try it if a proxy is used */ | |
79 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP); | |
80 #endif | |
0 | 81 |
82 /* if non zero, then set a range for RTP ports */ | |
83 int rtsp_rtp_port_min = 0; | |
84 int rtsp_rtp_port_max = 0; | |
85 | |
86 FFRTSPCallback *ff_rtsp_callback = NULL; | |
87 | |
88 static int rtsp_probe(AVProbeData *p) | |
89 { | |
90 if (strstart(p->filename, "rtsp:", NULL)) | |
91 return AVPROBE_SCORE_MAX; | |
92 return 0; | |
93 } | |
94 | |
95 static int redir_isspace(int c) | |
96 { | |
97 return (c == ' ' || c == '\t' || c == '\n' || c == '\r'); | |
98 } | |
99 | |
100 static void skip_spaces(const char **pp) | |
101 { | |
102 const char *p; | |
103 p = *pp; | |
104 while (redir_isspace(*p)) | |
105 p++; | |
106 *pp = p; | |
107 } | |
108 | |
109 static void get_word_sep(char *buf, int buf_size, const char *sep, | |
110 const char **pp) | |
111 { | |
112 const char *p; | |
113 char *q; | |
114 | |
115 p = *pp; | |
116 skip_spaces(&p); | |
117 q = buf; | |
118 while (!strchr(sep, *p) && *p != '\0') { | |
119 if ((q - buf) < buf_size - 1) | |
120 *q++ = *p; | |
121 p++; | |
122 } | |
123 if (buf_size > 0) | |
124 *q = '\0'; | |
125 *pp = p; | |
126 } | |
127 | |
128 static void get_word(char *buf, int buf_size, const char **pp) | |
129 { | |
130 const char *p; | |
131 char *q; | |
132 | |
133 p = *pp; | |
134 skip_spaces(&p); | |
135 q = buf; | |
136 while (!redir_isspace(*p) && *p != '\0') { | |
137 if ((q - buf) < buf_size - 1) | |
138 *q++ = *p; | |
139 p++; | |
140 } | |
141 if (buf_size > 0) | |
142 *q = '\0'; | |
143 *pp = p; | |
144 } | |
145 | |
146 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other | |
147 params>] */ | |
148 static int sdp_parse_rtpmap(AVCodecContext *codec, const char *p) | |
149 { | |
150 char buf[256]; | |
151 | |
152 /* codec name */ | |
153 get_word_sep(buf, sizeof(buf), "/", &p); | |
154 if (!strcmp(buf, "MP4V-ES")) { | |
155 codec->codec_id = CODEC_ID_MPEG4; | |
156 return 0; | |
157 } else { | |
158 return -1; | |
159 } | |
160 } | |
161 | |
162 /* return the length and optionnaly the data */ | |
163 static int hex_to_data(uint8_t *data, const char *p) | |
164 { | |
165 int c, len, v; | |
166 | |
167 len = 0; | |
168 v = 1; | |
169 for(;;) { | |
170 skip_spaces(&p); | |
171 if (p == '\0') | |
172 break; | |
173 c = toupper((unsigned char)*p++); | |
174 if (c >= '0' && c <= '9') | |
175 c = c - '0'; | |
176 else if (c >= 'A' && c <= 'F') | |
177 c = c - 'A' + 10; | |
178 else | |
179 break; | |
180 v = (v << 4) | c; | |
181 if (v & 0x100) { | |
182 if (data) | |
183 data[len] = v; | |
184 len++; | |
185 v = 1; | |
186 } | |
187 } | |
188 return len; | |
189 } | |
190 | |
191 static void sdp_parse_fmtp(AVCodecContext *codec, const char *p) | |
192 { | |
193 char attr[256]; | |
194 char value[4096]; | |
195 int len; | |
196 | |
197 /* loop on each attribute */ | |
198 for(;;) { | |
199 skip_spaces(&p); | |
200 if (*p == '\0') | |
201 break; | |
202 get_word_sep(attr, sizeof(attr), "=", &p); | |
203 if (*p == '=') | |
204 p++; | |
205 get_word_sep(value, sizeof(value), ";", &p); | |
206 if (*p == ';') | |
207 p++; | |
208 /* handle MPEG4 video */ | |
209 switch(codec->codec_id) { | |
210 case CODEC_ID_MPEG4: | |
211 if (!strcmp(attr, "config")) { | |
212 /* decode the hexa encoded parameter */ | |
213 len = hex_to_data(NULL, value); | |
214 codec->extradata = av_mallocz(len); | |
215 if (!codec->extradata) | |
216 goto fail; | |
217 codec->extradata_size = len; | |
218 hex_to_data(codec->extradata, value); | |
219 } | |
220 break; | |
221 default: | |
222 /* ignore data for other codecs */ | |
223 break; | |
224 } | |
225 fail: ; | |
226 // printf("'%s' = '%s'\n", attr, value); | |
227 } | |
228 } | |
229 | |
230 typedef struct SDPParseState { | |
231 /* SDP only */ | |
232 struct in_addr default_ip; | |
233 int default_ttl; | |
234 } SDPParseState; | |
235 | |
236 static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, | |
237 int letter, const char *buf) | |
238 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
239 RTSPState *rt = s->priv_data; |
0 | 240 char buf1[64], st_type[64]; |
241 const char *p; | |
242 int codec_type, payload_type, i; | |
243 AVStream *st; | |
244 RTSPStream *rtsp_st; | |
245 struct in_addr sdp_ip; | |
246 int ttl; | |
247 | |
248 #ifdef DEBUG | |
249 printf("sdp: %c='%s'\n", letter, buf); | |
250 #endif | |
251 | |
252 p = buf; | |
253 switch(letter) { | |
254 case 'c': | |
255 get_word(buf1, sizeof(buf1), &p); | |
256 if (strcmp(buf1, "IN") != 0) | |
257 return; | |
258 get_word(buf1, sizeof(buf1), &p); | |
259 if (strcmp(buf1, "IP4") != 0) | |
260 return; | |
261 get_word_sep(buf1, sizeof(buf1), "/", &p); | |
262 if (inet_aton(buf1, &sdp_ip) == 0) | |
263 return; | |
264 ttl = 16; | |
265 if (*p == '/') { | |
266 p++; | |
267 get_word_sep(buf1, sizeof(buf1), "/", &p); | |
268 ttl = atoi(buf1); | |
269 } | |
270 if (s->nb_streams == 0) { | |
271 s1->default_ip = sdp_ip; | |
272 s1->default_ttl = ttl; | |
273 } else { | |
274 st = s->streams[s->nb_streams - 1]; | |
275 rtsp_st = st->priv_data; | |
276 rtsp_st->sdp_ip = sdp_ip; | |
277 rtsp_st->sdp_ttl = ttl; | |
278 } | |
279 break; | |
280 case 's': | |
281 pstrcpy(s->title, sizeof(s->title), p); | |
282 break; | |
283 case 'i': | |
284 if (s->nb_streams == 0) { | |
285 pstrcpy(s->comment, sizeof(s->comment), p); | |
286 break; | |
287 } | |
288 break; | |
289 case 'm': | |
290 /* new stream */ | |
291 get_word(st_type, sizeof(st_type), &p); | |
292 if (!strcmp(st_type, "audio")) { | |
293 codec_type = CODEC_TYPE_AUDIO; | |
294 } else if (!strcmp(st_type, "video")) { | |
295 codec_type = CODEC_TYPE_VIDEO; | |
296 } else { | |
297 return; | |
298 } | |
299 rtsp_st = av_mallocz(sizeof(RTSPStream)); | |
300 if (!rtsp_st) | |
301 return; | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
302 rtsp_st->stream_index = -1; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
303 dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); |
0 | 304 |
305 rtsp_st->sdp_ip = s1->default_ip; | |
306 rtsp_st->sdp_ttl = s1->default_ttl; | |
307 | |
308 get_word(buf1, sizeof(buf1), &p); /* port */ | |
309 rtsp_st->sdp_port = atoi(buf1); | |
310 | |
311 get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */ | |
312 | |
313 /* XXX: handle list of formats */ | |
314 get_word(buf1, sizeof(buf1), &p); /* format list */ | |
315 rtsp_st->sdp_payload_type = atoi(buf1); | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
316 |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
317 if (rtsp_st->sdp_payload_type == RTP_PT_MPEG2TS) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
318 /* no corresponding stream */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
319 } else { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
320 st = av_new_stream(s, 0); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
321 if (!st) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
322 return; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
323 st->priv_data = rtsp_st; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
324 rtsp_st->stream_index = st->index; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
325 st->codec.codec_type = codec_type; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
326 if (rtsp_st->sdp_payload_type < 96) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
327 /* if standard payload type, we can find the codec right now */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
328 rtp_get_codec_info(&st->codec, rtsp_st->sdp_payload_type); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
329 } |
0 | 330 } |
331 /* put a default control url */ | |
332 pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename); | |
333 break; | |
334 case 'a': | |
335 if (strstart(p, "control:", &p) && s->nb_streams > 0) { | |
336 char proto[32]; | |
337 /* get the control url */ | |
338 st = s->streams[s->nb_streams - 1]; | |
339 rtsp_st = st->priv_data; | |
340 | |
341 /* XXX: may need to add full url resolution */ | |
511
056991ab9f10
HTTP Authentication Patch by (Petr Doubek <doubek at vision dot ee dot ethz dot ch>)
michael
parents:
391
diff
changeset
|
342 url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p); |
0 | 343 if (proto[0] == '\0') { |
344 /* relative control URL */ | |
345 pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/"); | |
346 pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), p); | |
347 } else { | |
348 pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), p); | |
349 } | |
350 } else if (strstart(p, "rtpmap:", &p)) { | |
351 /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ | |
352 get_word(buf1, sizeof(buf1), &p); | |
353 payload_type = atoi(buf1); | |
354 for(i = 0; i < s->nb_streams;i++) { | |
355 st = s->streams[i]; | |
356 rtsp_st = st->priv_data; | |
357 if (rtsp_st->sdp_payload_type == payload_type) { | |
358 sdp_parse_rtpmap(&st->codec, p); | |
359 } | |
360 } | |
361 } else if (strstart(p, "fmtp:", &p)) { | |
362 /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ | |
363 get_word(buf1, sizeof(buf1), &p); | |
364 payload_type = atoi(buf1); | |
365 for(i = 0; i < s->nb_streams;i++) { | |
366 st = s->streams[i]; | |
367 rtsp_st = st->priv_data; | |
368 if (rtsp_st->sdp_payload_type == payload_type) { | |
369 sdp_parse_fmtp(&st->codec, p); | |
370 } | |
371 } | |
372 } | |
373 break; | |
374 } | |
375 } | |
376 | |
64 | 377 static int sdp_parse(AVFormatContext *s, const char *content) |
0 | 378 { |
379 const char *p; | |
380 int letter; | |
381 char buf[1024], *q; | |
382 SDPParseState sdp_parse_state, *s1 = &sdp_parse_state; | |
383 | |
384 memset(s1, 0, sizeof(SDPParseState)); | |
385 p = content; | |
386 for(;;) { | |
387 skip_spaces(&p); | |
388 letter = *p; | |
389 if (letter == '\0') | |
390 break; | |
391 p++; | |
392 if (*p != '=') | |
393 goto next_line; | |
394 p++; | |
395 /* get the content */ | |
396 q = buf; | |
172 | 397 while (*p != '\n' && *p != '\r' && *p != '\0') { |
0 | 398 if ((q - buf) < sizeof(buf) - 1) |
399 *q++ = *p; | |
400 p++; | |
401 } | |
402 *q = '\0'; | |
403 sdp_parse_line(s, s1, letter, buf); | |
404 next_line: | |
405 while (*p != '\n' && *p != '\0') | |
406 p++; | |
407 if (*p == '\n') | |
408 p++; | |
409 } | |
410 return 0; | |
411 } | |
412 | |
413 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) | |
414 { | |
415 const char *p; | |
416 int v; | |
417 | |
418 p = *pp; | |
419 skip_spaces(&p); | |
420 v = strtol(p, (char **)&p, 10); | |
421 if (*p == '-') { | |
422 p++; | |
423 *min_ptr = v; | |
424 v = strtol(p, (char **)&p, 10); | |
425 *max_ptr = v; | |
426 } else { | |
427 *min_ptr = v; | |
428 *max_ptr = v; | |
429 } | |
430 *pp = p; | |
431 } | |
432 | |
433 /* XXX: only one transport specification is parsed */ | |
434 static void rtsp_parse_transport(RTSPHeader *reply, const char *p) | |
435 { | |
436 char transport_protocol[16]; | |
437 char profile[16]; | |
438 char lower_transport[16]; | |
439 char parameter[16]; | |
440 RTSPTransportField *th; | |
441 char buf[256]; | |
442 | |
443 reply->nb_transports = 0; | |
444 | |
445 for(;;) { | |
446 skip_spaces(&p); | |
447 if (*p == '\0') | |
448 break; | |
449 | |
450 th = &reply->transports[reply->nb_transports]; | |
451 | |
452 get_word_sep(transport_protocol, sizeof(transport_protocol), | |
453 "/", &p); | |
454 if (*p == '/') | |
455 p++; | |
456 get_word_sep(profile, sizeof(profile), "/;,", &p); | |
457 lower_transport[0] = '\0'; | |
458 if (*p == '/') { | |
172 | 459 p++; |
0 | 460 get_word_sep(lower_transport, sizeof(lower_transport), |
461 ";,", &p); | |
462 } | |
172 | 463 if (!strcasecmp(lower_transport, "TCP")) |
0 | 464 th->protocol = RTSP_PROTOCOL_RTP_TCP; |
465 else | |
466 th->protocol = RTSP_PROTOCOL_RTP_UDP; | |
467 | |
468 if (*p == ';') | |
469 p++; | |
470 /* get each parameter */ | |
471 while (*p != '\0' && *p != ',') { | |
472 get_word_sep(parameter, sizeof(parameter), "=;,", &p); | |
473 if (!strcmp(parameter, "port")) { | |
474 if (*p == '=') { | |
475 p++; | |
476 rtsp_parse_range(&th->port_min, &th->port_max, &p); | |
477 } | |
478 } else if (!strcmp(parameter, "client_port")) { | |
479 if (*p == '=') { | |
480 p++; | |
481 rtsp_parse_range(&th->client_port_min, | |
482 &th->client_port_max, &p); | |
483 } | |
484 } else if (!strcmp(parameter, "server_port")) { | |
485 if (*p == '=') { | |
486 p++; | |
487 rtsp_parse_range(&th->server_port_min, | |
488 &th->server_port_max, &p); | |
489 } | |
490 } else if (!strcmp(parameter, "interleaved")) { | |
491 if (*p == '=') { | |
492 p++; | |
493 rtsp_parse_range(&th->interleaved_min, | |
494 &th->interleaved_max, &p); | |
495 } | |
496 } else if (!strcmp(parameter, "multicast")) { | |
497 if (th->protocol == RTSP_PROTOCOL_RTP_UDP) | |
498 th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST; | |
499 } else if (!strcmp(parameter, "ttl")) { | |
500 if (*p == '=') { | |
501 p++; | |
502 th->ttl = strtol(p, (char **)&p, 10); | |
503 } | |
504 } else if (!strcmp(parameter, "destination")) { | |
505 struct in_addr ipaddr; | |
506 | |
507 if (*p == '=') { | |
508 p++; | |
509 get_word_sep(buf, sizeof(buf), ";,", &p); | |
510 if (inet_aton(buf, &ipaddr)) | |
511 th->destination = ntohl(ipaddr.s_addr); | |
512 } | |
513 } | |
514 while (*p != ';' && *p != '\0' && *p != ',') | |
515 p++; | |
516 if (*p == ';') | |
517 p++; | |
518 } | |
519 if (*p == ',') | |
520 p++; | |
521 | |
522 reply->nb_transports++; | |
523 } | |
524 } | |
525 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
526 static void rtsp_parse_range_npt(RTSPHeader *reply, const char *p) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
527 { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
528 char buf[256]; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
529 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
530 skip_spaces(&p); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
531 if (!stristart(p, "npt=", &p)) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
532 return; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
533 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
534 reply->range_start = AV_NOPTS_VALUE; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
535 reply->range_end = AV_NOPTS_VALUE; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
536 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
537 get_word_sep(buf, sizeof(buf), "-", &p); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
538 reply->range_start = parse_date(buf, 1); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
539 if (*p == '-') { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
540 p++; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
541 get_word_sep(buf, sizeof(buf), "-", &p); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
542 reply->range_end = parse_date(buf, 1); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
543 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
544 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
545 |
0 | 546 void rtsp_parse_line(RTSPHeader *reply, const char *buf) |
547 { | |
548 const char *p; | |
549 | |
550 /* NOTE: we do case independent match for broken servers */ | |
551 p = buf; | |
552 if (stristart(p, "Session:", &p)) { | |
553 get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); | |
554 } else if (stristart(p, "Content-Length:", &p)) { | |
555 reply->content_length = strtol(p, NULL, 10); | |
556 } else if (stristart(p, "Transport:", &p)) { | |
557 rtsp_parse_transport(reply, p); | |
558 } else if (stristart(p, "CSeq:", &p)) { | |
559 reply->seq = strtol(p, NULL, 10); | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
560 } else if (stristart(p, "Range:", &p)) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
561 rtsp_parse_range_npt(reply, p); |
0 | 562 } |
563 } | |
564 | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
565 static int url_readbuf(URLContext *h, unsigned char *buf, int size) |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
566 { |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
567 int ret, len; |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
568 |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
569 len = 0; |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
570 while (len < size) { |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
571 ret = url_read(h, buf+len, size-len); |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
572 if (ret < 1) |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
573 return ret; |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
574 len += ret; |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
575 } |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
576 return len; |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
577 } |
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
578 |
179 | 579 /* skip a RTP/TCP interleaved packet */ |
580 static void rtsp_skip_packet(AVFormatContext *s) | |
581 { | |
582 RTSPState *rt = s->priv_data; | |
583 int ret, len, len1; | |
584 uint8_t buf[1024]; | |
585 | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
586 ret = url_readbuf(rt->rtsp_hd, buf, 3); |
179 | 587 if (ret != 3) |
588 return; | |
589 len = (buf[1] << 8) | buf[2]; | |
590 #ifdef DEBUG | |
591 printf("skipping RTP packet len=%d\n", len); | |
592 #endif | |
593 /* skip payload */ | |
594 while (len > 0) { | |
595 len1 = len; | |
596 if (len1 > sizeof(buf)) | |
597 len1 = sizeof(buf); | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
598 ret = url_readbuf(rt->rtsp_hd, buf, len1); |
179 | 599 if (ret != len1) |
600 return; | |
601 len -= len1; | |
602 } | |
603 } | |
0 | 604 |
605 static void rtsp_send_cmd(AVFormatContext *s, | |
606 const char *cmd, RTSPHeader *reply, | |
607 unsigned char **content_ptr) | |
608 { | |
609 RTSPState *rt = s->priv_data; | |
610 char buf[4096], buf1[1024], *q; | |
611 unsigned char ch; | |
612 const char *p; | |
613 int content_length, line_count; | |
614 unsigned char *content = NULL; | |
615 | |
616 memset(reply, 0, sizeof(RTSPHeader)); | |
617 | |
618 rt->seq++; | |
619 pstrcpy(buf, sizeof(buf), cmd); | |
172 | 620 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq); |
0 | 621 pstrcat(buf, sizeof(buf), buf1); |
622 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) { | |
172 | 623 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id); |
0 | 624 pstrcat(buf, sizeof(buf), buf1); |
625 } | |
172 | 626 pstrcat(buf, sizeof(buf), "\r\n"); |
0 | 627 #ifdef DEBUG |
628 printf("Sending:\n%s--\n", buf); | |
629 #endif | |
630 url_write(rt->rtsp_hd, buf, strlen(buf)); | |
631 | |
632 /* parse reply (XXX: use buffers) */ | |
633 line_count = 0; | |
634 rt->last_reply[0] = '\0'; | |
635 for(;;) { | |
636 q = buf; | |
637 for(;;) { | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
638 if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1) |
0 | 639 break; |
640 if (ch == '\n') | |
641 break; | |
179 | 642 if (ch == '$') { |
643 /* XXX: only parse it if first char on line ? */ | |
644 rtsp_skip_packet(s); | |
645 } else if (ch != '\r') { | |
0 | 646 if ((q - buf) < sizeof(buf) - 1) |
647 *q++ = ch; | |
648 } | |
649 } | |
650 *q = '\0'; | |
651 #ifdef DEBUG | |
652 printf("line='%s'\n", buf); | |
653 #endif | |
654 /* test if last line */ | |
655 if (buf[0] == '\0') | |
656 break; | |
657 p = buf; | |
658 if (line_count == 0) { | |
659 /* get reply code */ | |
660 get_word(buf1, sizeof(buf1), &p); | |
661 get_word(buf1, sizeof(buf1), &p); | |
662 reply->status_code = atoi(buf1); | |
663 } else { | |
664 rtsp_parse_line(reply, p); | |
665 pstrcat(rt->last_reply, sizeof(rt->last_reply), p); | |
666 pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n"); | |
667 } | |
668 line_count++; | |
669 } | |
670 | |
671 if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') | |
672 pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id); | |
673 | |
674 content_length = reply->content_length; | |
675 if (content_length > 0) { | |
676 /* leave some room for a trailing '\0' (useful for simple parsing) */ | |
677 content = av_malloc(content_length + 1); | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
678 (void)url_readbuf(rt->rtsp_hd, content, content_length); |
0 | 679 content[content_length] = '\0'; |
680 } | |
681 if (content_ptr) | |
682 *content_ptr = content; | |
683 } | |
684 | |
685 /* useful for modules: set RTSP callback function */ | |
686 | |
687 void rtsp_set_callback(FFRTSPCallback *rtsp_cb) | |
688 { | |
689 ff_rtsp_callback = rtsp_cb; | |
690 } | |
691 | |
692 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
693 /* close and free RTSP streams */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
694 static void rtsp_close_streams(RTSPState *rt) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
695 { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
696 int i; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
697 RTSPStream *rtsp_st; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
698 |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
699 for(i=0;i<rt->nb_rtsp_streams;i++) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
700 rtsp_st = rt->rtsp_streams[i]; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
701 if (rtsp_st) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
702 if (rtsp_st->rtp_ctx) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
703 rtp_parse_close(rtsp_st->rtp_ctx); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
704 if (rtsp_st->rtp_handle) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
705 url_close(rtsp_st->rtp_handle); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
706 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
707 av_free(rtsp_st); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
708 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
709 av_free(rt->rtsp_streams); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
710 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
711 |
0 | 712 static int rtsp_read_header(AVFormatContext *s, |
713 AVFormatParameters *ap) | |
714 { | |
715 RTSPState *rt = s->priv_data; | |
716 char host[1024], path[1024], tcpname[1024], cmd[2048]; | |
717 URLContext *rtsp_hd; | |
718 int port, i, ret, err; | |
719 RTSPHeader reply1, *reply = &reply1; | |
720 unsigned char *content = NULL; | |
721 RTSPStream *rtsp_st; | |
722 int protocol_mask; | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
723 AVStream *st; |
0 | 724 |
725 /* extract hostname and port */ | |
511
056991ab9f10
HTTP Authentication Patch by (Petr Doubek <doubek at vision dot ee dot ethz dot ch>)
michael
parents:
391
diff
changeset
|
726 url_split(NULL, 0, NULL, 0, |
0 | 727 host, sizeof(host), &port, path, sizeof(path), s->filename); |
728 if (port < 0) | |
729 port = RTSP_DEFAULT_PORT; | |
730 | |
731 /* open the tcp connexion */ | |
732 snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port); | |
733 if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) | |
734 return AVERROR_IO; | |
735 rt->rtsp_hd = rtsp_hd; | |
736 rt->seq = 0; | |
737 | |
738 /* describe the stream */ | |
739 snprintf(cmd, sizeof(cmd), | |
172 | 740 "DESCRIBE %s RTSP/1.0\r\n" |
741 "Accept: application/sdp\r\n", | |
0 | 742 s->filename); |
743 rtsp_send_cmd(s, cmd, reply, &content); | |
744 if (!content) { | |
745 err = AVERROR_INVALIDDATA; | |
746 goto fail; | |
747 } | |
748 if (reply->status_code != RTSP_STATUS_OK) { | |
749 err = AVERROR_INVALIDDATA; | |
750 goto fail; | |
751 } | |
752 | |
753 /* now we got the SDP description, we parse it */ | |
754 ret = sdp_parse(s, (const char *)content); | |
755 av_freep(&content); | |
756 if (ret < 0) { | |
757 err = AVERROR_INVALIDDATA; | |
758 goto fail; | |
759 } | |
760 | |
761 protocol_mask = rtsp_default_protocols; | |
762 | |
763 /* for each stream, make the setup request */ | |
764 /* XXX: we assume the same server is used for the control of each | |
765 RTSP stream */ | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
766 for(i=0;i<rt->nb_rtsp_streams;i++) { |
0 | 767 char transport[2048]; |
768 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
769 rtsp_st = rt->rtsp_streams[i]; |
0 | 770 |
771 /* compute available transports */ | |
772 transport[0] = '\0'; | |
773 | |
774 /* RTP/UDP */ | |
775 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) { | |
776 char buf[256]; | |
777 int j; | |
778 | |
779 /* first try in specified port range */ | |
780 if (rtsp_rtp_port_min != 0) { | |
781 for(j=rtsp_rtp_port_min;j<=rtsp_rtp_port_max;j++) { | |
782 snprintf(buf, sizeof(buf), "rtp://?localport=%d", j); | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
783 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) |
0 | 784 goto rtp_opened; |
785 } | |
786 } | |
787 | |
788 /* then try on any port */ | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
789 if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
790 err = AVERROR_INVALIDDATA; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
791 goto fail; |
0 | 792 } |
793 | |
794 rtp_opened: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
795 port = rtp_get_local_port(rtsp_st->rtp_handle); |
0 | 796 if (transport[0] != '\0') |
797 pstrcat(transport, sizeof(transport), ","); | |
798 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, | |
799 "RTP/AVP/UDP;unicast;client_port=%d-%d", | |
800 port, port + 1); | |
801 } | |
802 | |
803 /* RTP/TCP */ | |
804 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) { | |
805 if (transport[0] != '\0') | |
806 pstrcat(transport, sizeof(transport), ","); | |
807 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, | |
808 "RTP/AVP/TCP"); | |
809 } | |
810 | |
811 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) { | |
812 if (transport[0] != '\0') | |
813 pstrcat(transport, sizeof(transport), ","); | |
814 snprintf(transport + strlen(transport), | |
815 sizeof(transport) - strlen(transport) - 1, | |
816 "RTP/AVP/UDP;multicast"); | |
817 } | |
818 snprintf(cmd, sizeof(cmd), | |
172 | 819 "SETUP %s RTSP/1.0\r\n" |
820 "Transport: %s\r\n", | |
0 | 821 rtsp_st->control_url, transport); |
822 rtsp_send_cmd(s, cmd, reply, NULL); | |
823 if (reply->status_code != RTSP_STATUS_OK || | |
824 reply->nb_transports != 1) { | |
825 err = AVERROR_INVALIDDATA; | |
826 goto fail; | |
827 } | |
828 | |
829 /* XXX: same protocol for all streams is required */ | |
830 if (i > 0) { | |
831 if (reply->transports[0].protocol != rt->protocol) { | |
832 err = AVERROR_INVALIDDATA; | |
833 goto fail; | |
834 } | |
835 } else { | |
836 rt->protocol = reply->transports[0].protocol; | |
837 } | |
838 | |
839 /* close RTP connection if not choosen */ | |
840 if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP && | |
841 (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
842 url_close(rtsp_st->rtp_handle); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
843 rtsp_st->rtp_handle = NULL; |
0 | 844 } |
845 | |
846 switch(reply->transports[0].protocol) { | |
847 case RTSP_PROTOCOL_RTP_TCP: | |
848 rtsp_st->interleaved_min = reply->transports[0].interleaved_min; | |
849 rtsp_st->interleaved_max = reply->transports[0].interleaved_max; | |
850 break; | |
851 | |
852 case RTSP_PROTOCOL_RTP_UDP: | |
853 { | |
854 char url[1024]; | |
855 | |
856 /* XXX: also use address if specified */ | |
857 snprintf(url, sizeof(url), "rtp://%s:%d", | |
858 host, reply->transports[0].server_port_min); | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
859 if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { |
0 | 860 err = AVERROR_INVALIDDATA; |
861 goto fail; | |
862 } | |
863 } | |
864 break; | |
865 case RTSP_PROTOCOL_RTP_UDP_MULTICAST: | |
866 { | |
867 char url[1024]; | |
868 int ttl; | |
869 | |
870 ttl = reply->transports[0].ttl; | |
871 if (!ttl) | |
872 ttl = 16; | |
873 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", | |
874 host, | |
875 reply->transports[0].server_port_min, | |
876 ttl); | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
877 if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) { |
0 | 878 err = AVERROR_INVALIDDATA; |
879 goto fail; | |
880 } | |
881 } | |
882 break; | |
883 } | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
884 /* open the RTP context */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
885 st = NULL; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
886 if (rtsp_st->stream_index >= 0) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
887 st = s->streams[rtsp_st->stream_index]; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
888 if (!st) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
889 s->ctx_flags |= AVFMTCTX_NOHEADER; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
890 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
891 if (!rtsp_st->rtp_ctx) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
892 err = AVERROR_NOMEM; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
893 goto fail; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
894 } |
0 | 895 } |
896 | |
897 /* use callback if available to extend setup */ | |
898 if (ff_rtsp_callback) { | |
899 if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, | |
900 NULL, 0, rt->last_reply) < 0) { | |
901 err = AVERROR_INVALIDDATA; | |
902 goto fail; | |
903 } | |
904 } | |
905 | |
906 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
907 rt->state = RTSP_STATE_IDLE; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
908 rt->seek_timestamp = 0; /* default is to start stream at position |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
909 zero */ |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
910 if (ap && ap->initial_pause) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
911 /* do not start immediately */ |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
912 } else { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
913 if (rtsp_read_play(s) < 0) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
914 err = AVERROR_INVALIDDATA; |
0 | 915 goto fail; |
916 } | |
917 } | |
918 return 0; | |
919 fail: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
920 rtsp_close_streams(rt); |
0 | 921 av_freep(&content); |
922 url_close(rt->rtsp_hd); | |
923 return err; | |
924 } | |
925 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
926 static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
927 uint8_t *buf, int buf_size) |
0 | 928 { |
929 RTSPState *rt = s->priv_data; | |
172 | 930 int id, len, i, ret; |
0 | 931 RTSPStream *rtsp_st; |
932 | |
172 | 933 #ifdef DEBUG_RTP_TCP |
934 printf("tcp_read_packet:\n"); | |
935 #endif | |
0 | 936 redo: |
937 for(;;) { | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
938 ret = url_readbuf(rt->rtsp_hd, buf, 1); |
172 | 939 #ifdef DEBUG_RTP_TCP |
940 printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]); | |
941 #endif | |
942 if (ret != 1) | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
943 return -1; |
172 | 944 if (buf[0] == '$') |
0 | 945 break; |
946 } | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
947 ret = url_readbuf(rt->rtsp_hd, buf, 3); |
172 | 948 if (ret != 3) |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
949 return -1; |
172 | 950 id = buf[0]; |
951 len = (buf[1] << 8) | buf[2]; | |
952 #ifdef DEBUG_RTP_TCP | |
953 printf("id=%d len=%d\n", id, len); | |
954 #endif | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
955 if (len > buf_size || len < 12) |
0 | 956 goto redo; |
957 /* get the data */ | |
391
1cf22651d33b
support url_read which reads less then requested patch by (Leon van Stuivenberg <l dot vanstuivenberg at chello dot nl>)
michael
parents:
370
diff
changeset
|
958 ret = url_readbuf(rt->rtsp_hd, buf, len); |
172 | 959 if (ret != len) |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
960 return -1; |
172 | 961 |
0 | 962 /* find the matching stream */ |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
963 for(i = 0; i < rt->nb_rtsp_streams; i++) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
964 rtsp_st = rt->rtsp_streams[i]; |
172 | 965 if (id >= rtsp_st->interleaved_min && |
966 id <= rtsp_st->interleaved_max) | |
0 | 967 goto found; |
968 } | |
969 goto redo; | |
970 found: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
971 *prtsp_st = rtsp_st; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
972 return len; |
0 | 973 } |
974 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
975 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
976 uint8_t *buf, int buf_size) |
0 | 977 { |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
978 RTSPState *rt = s->priv_data; |
0 | 979 RTSPStream *rtsp_st; |
980 fd_set rfds; | |
981 int fd1, fd2, fd_max, n, i, ret; | |
982 struct timeval tv; | |
983 | |
984 for(;;) { | |
179 | 985 if (url_interrupt_cb()) |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
986 return -1; |
0 | 987 FD_ZERO(&rfds); |
988 fd_max = -1; | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
989 for(i = 0; i < rt->nb_rtsp_streams; i++) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
990 rtsp_st = rt->rtsp_streams[i]; |
0 | 991 /* currently, we cannot probe RTCP handle because of blocking restrictions */ |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
992 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2); |
0 | 993 if (fd1 > fd_max) |
994 fd_max = fd1; | |
995 FD_SET(fd1, &rfds); | |
996 } | |
997 tv.tv_sec = 0; | |
179 | 998 tv.tv_usec = 100 * 1000; |
0 | 999 n = select(fd_max + 1, &rfds, NULL, NULL, &tv); |
1000 if (n > 0) { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1001 for(i = 0; i < rt->nb_rtsp_streams; i++) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1002 rtsp_st = rt->rtsp_streams[i]; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1003 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2); |
0 | 1004 if (FD_ISSET(fd1, &rfds)) { |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1005 ret = url_read(rtsp_st->rtp_handle, buf, buf_size); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1006 if (ret > 0) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1007 *prtsp_st = rtsp_st; |
0 | 1008 return ret; |
1009 } | |
1010 } | |
1011 } | |
1012 } | |
1013 } | |
1014 } | |
1015 | |
1016 static int rtsp_read_packet(AVFormatContext *s, | |
1017 AVPacket *pkt) | |
1018 { | |
1019 RTSPState *rt = s->priv_data; | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1020 RTSPStream *rtsp_st; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1021 int ret, len; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1022 uint8_t buf[RTP_MAX_PACKET_LENGTH]; |
0 | 1023 |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1024 /* get next frames from the same RTP packet */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1025 if (rt->cur_rtp) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1026 ret = rtp_parse_packet(rt->cur_rtp, pkt, NULL, 0); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1027 if (ret == 0) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1028 rt->cur_rtp = NULL; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1029 return 0; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1030 } else if (ret == 1) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1031 return 0; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1032 } else { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1033 rt->cur_rtp = NULL; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1034 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1035 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1036 |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1037 /* read next RTP packet */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1038 redo: |
0 | 1039 switch(rt->protocol) { |
1040 default: | |
1041 case RTSP_PROTOCOL_RTP_TCP: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1042 len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf)); |
0 | 1043 break; |
1044 case RTSP_PROTOCOL_RTP_UDP: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1045 case RTSP_PROTOCOL_RTP_UDP_MULTICAST: |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1046 len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf)); |
0 | 1047 break; |
1048 } | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1049 if (len < 0) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1050 return AVERROR_IO; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1051 ret = rtp_parse_packet(rtsp_st->rtp_ctx, pkt, buf, len); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1052 if (ret < 0) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1053 goto redo; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1054 if (ret == 1) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1055 /* more packets may follow, so we save the RTP context */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1056 rt->cur_rtp = rtsp_st->rtp_ctx; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1057 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1058 return 0; |
0 | 1059 } |
1060 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1061 static int rtsp_read_play(AVFormatContext *s) |
179 | 1062 { |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1063 RTSPState *rt = s->priv_data; |
179 | 1064 RTSPHeader reply1, *reply = &reply1; |
1065 char cmd[1024]; | |
1066 | |
370
845f9de2c883
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
304
diff
changeset
|
1067 av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state); |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1068 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1069 if (rt->state == RTSP_STATE_PAUSED) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1070 snprintf(cmd, sizeof(cmd), |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1071 "PLAY %s RTSP/1.0\r\n", |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1072 s->filename); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1073 } else { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1074 snprintf(cmd, sizeof(cmd), |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1075 "PLAY %s RTSP/1.0\r\n" |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1076 "Range: npt=%0.3f-\r\n", |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1077 s->filename, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1078 (double)rt->seek_timestamp / AV_TIME_BASE); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1079 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1080 rtsp_send_cmd(s, cmd, reply, NULL); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1081 if (reply->status_code != RTSP_STATUS_OK) { |
179 | 1082 return -1; |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1083 } else { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1084 rt->state = RTSP_STATE_PLAYING; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1085 return 0; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1086 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1087 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1088 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1089 /* pause the stream */ |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1090 static int rtsp_read_pause(AVFormatContext *s) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1091 { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1092 RTSPState *rt = s->priv_data; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1093 RTSPHeader reply1, *reply = &reply1; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1094 char cmd[1024]; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1095 |
179 | 1096 rt = s->priv_data; |
1097 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1098 if (rt->state != RTSP_STATE_PLAYING) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1099 return 0; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1100 |
179 | 1101 snprintf(cmd, sizeof(cmd), |
1102 "PAUSE %s RTSP/1.0\r\n", | |
1103 s->filename); | |
1104 rtsp_send_cmd(s, cmd, reply, NULL); | |
1105 if (reply->status_code != RTSP_STATUS_OK) { | |
1106 return -1; | |
1107 } else { | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1108 rt->state = RTSP_STATE_PAUSED; |
179 | 1109 return 0; |
1110 } | |
1111 } | |
1112 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1113 static int rtsp_read_seek(AVFormatContext *s, int stream_index, |
558 | 1114 int64_t timestamp, int flags) |
179 | 1115 { |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1116 RTSPState *rt = s->priv_data; |
179 | 1117 |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1118 rt->seek_timestamp = timestamp; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1119 switch(rt->state) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1120 default: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1121 case RTSP_STATE_IDLE: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1122 break; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1123 case RTSP_STATE_PLAYING: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1124 if (rtsp_read_play(s) != 0) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1125 return -1; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1126 break; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1127 case RTSP_STATE_PAUSED: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1128 rt->state = RTSP_STATE_IDLE; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1129 break; |
179 | 1130 } |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1131 return 0; |
179 | 1132 } |
1133 | |
0 | 1134 static int rtsp_read_close(AVFormatContext *s) |
1135 { | |
1136 RTSPState *rt = s->priv_data; | |
1137 RTSPHeader reply1, *reply = &reply1; | |
1138 char cmd[1024]; | |
1139 | |
172 | 1140 #if 0 |
0 | 1141 /* NOTE: it is valid to flush the buffer here */ |
1142 if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) { | |
1143 url_fclose(&rt->rtsp_gb); | |
1144 } | |
172 | 1145 #endif |
0 | 1146 snprintf(cmd, sizeof(cmd), |
172 | 1147 "TEARDOWN %s RTSP/1.0\r\n", |
0 | 1148 s->filename); |
1149 rtsp_send_cmd(s, cmd, reply, NULL); | |
1150 | |
1151 if (ff_rtsp_callback) { | |
1152 ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id, | |
1153 NULL, 0, NULL); | |
1154 } | |
1155 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1156 rtsp_close_streams(rt); |
0 | 1157 url_close(rt->rtsp_hd); |
1158 return 0; | |
1159 } | |
1160 | |
179 | 1161 AVInputFormat rtsp_demux = { |
0 | 1162 "rtsp", |
1163 "RTSP input format", | |
1164 sizeof(RTSPState), | |
1165 rtsp_probe, | |
1166 rtsp_read_header, | |
1167 rtsp_read_packet, | |
1168 rtsp_read_close, | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1169 rtsp_read_seek, |
0 | 1170 .flags = AVFMT_NOFILE, |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1171 .read_play = rtsp_read_play, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1172 .read_pause = rtsp_read_pause, |
0 | 1173 }; |
1174 | |
1175 static int sdp_probe(AVProbeData *p1) | |
1176 { | |
1177 const char *p; | |
1178 | |
1179 /* we look for a line beginning "c=IN IP4" */ | |
1180 p = p1->buf; | |
1181 while (*p != '\0') { | |
1182 if (strstart(p, "c=IN IP4", NULL)) | |
1183 return AVPROBE_SCORE_MAX / 2; | |
1184 p = strchr(p, '\n'); | |
1185 if (!p) | |
1186 break; | |
1187 p++; | |
1188 if (*p == '\r') | |
1189 p++; | |
1190 } | |
1191 return 0; | |
1192 } | |
1193 | |
1194 #define SDP_MAX_SIZE 8192 | |
1195 | |
1196 static int sdp_read_header(AVFormatContext *s, | |
1197 AVFormatParameters *ap) | |
1198 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1199 RTSPState *rt = s->priv_data; |
0 | 1200 RTSPStream *rtsp_st; |
1201 int size, i, err; | |
1202 char *content; | |
1203 char url[1024]; | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1204 AVStream *st; |
0 | 1205 |
1206 /* read the whole sdp file */ | |
1207 /* XXX: better loading */ | |
1208 content = av_malloc(SDP_MAX_SIZE); | |
1209 size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1); | |
1210 if (size <= 0) { | |
1211 av_free(content); | |
1212 return AVERROR_INVALIDDATA; | |
1213 } | |
1214 content[size] ='\0'; | |
1215 | |
1216 sdp_parse(s, content); | |
1217 av_free(content); | |
1218 | |
1219 /* open each RTP stream */ | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1220 for(i=0;i<rt->nb_rtsp_streams;i++) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1221 rtsp_st = rt->rtsp_streams[i]; |
0 | 1222 |
1223 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", | |
1224 inet_ntoa(rtsp_st->sdp_ip), | |
1225 rtsp_st->sdp_port, | |
1226 rtsp_st->sdp_ttl); | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1227 if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) { |
0 | 1228 err = AVERROR_INVALIDDATA; |
1229 goto fail; | |
1230 } | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1231 /* open the RTP context */ |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1232 st = NULL; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1233 if (rtsp_st->stream_index >= 0) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1234 st = s->streams[rtsp_st->stream_index]; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1235 if (!st) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1236 s->ctx_flags |= AVFMTCTX_NOHEADER; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1237 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type); |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1238 if (!rtsp_st->rtp_ctx) { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1239 err = AVERROR_NOMEM; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1240 goto fail; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1241 } |
0 | 1242 } |
1243 return 0; | |
1244 fail: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1245 rtsp_close_streams(rt); |
0 | 1246 return err; |
1247 } | |
1248 | |
1249 static int sdp_read_packet(AVFormatContext *s, | |
1250 AVPacket *pkt) | |
1251 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1252 return rtsp_read_packet(s, pkt); |
0 | 1253 } |
1254 | |
1255 static int sdp_read_close(AVFormatContext *s) | |
1256 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1257 RTSPState *rt = s->priv_data; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1258 rtsp_close_streams(rt); |
0 | 1259 return 0; |
1260 } | |
1261 | |
1262 | |
1263 static AVInputFormat sdp_demux = { | |
1264 "sdp", | |
1265 "SDP", | |
1266 sizeof(RTSPState), | |
1267 sdp_probe, | |
1268 sdp_read_header, | |
1269 sdp_read_packet, | |
1270 sdp_read_close, | |
1271 }; | |
1272 | |
1273 | |
1274 /* dummy redirector format (used directly in av_open_input_file now) */ | |
1275 static int redir_probe(AVProbeData *pd) | |
1276 { | |
1277 const char *p; | |
1278 p = pd->buf; | |
1279 while (redir_isspace(*p)) | |
1280 p++; | |
1281 if (strstart(p, "http://", NULL) || | |
1282 strstart(p, "rtsp://", NULL)) | |
1283 return AVPROBE_SCORE_MAX; | |
1284 return 0; | |
1285 } | |
1286 | |
1287 /* called from utils.c */ | |
1288 int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f) | |
1289 { | |
1290 char buf[4096], *q; | |
1291 int c; | |
1292 AVFormatContext *ic = NULL; | |
1293 | |
1294 /* parse each URL and try to open it */ | |
1295 c = url_fgetc(f); | |
1296 while (c != URL_EOF) { | |
1297 /* skip spaces */ | |
1298 for(;;) { | |
1299 if (!redir_isspace(c)) | |
1300 break; | |
1301 c = url_fgetc(f); | |
1302 } | |
1303 if (c == URL_EOF) | |
1304 break; | |
1305 /* record url */ | |
1306 q = buf; | |
1307 for(;;) { | |
1308 if (c == URL_EOF || redir_isspace(c)) | |
1309 break; | |
1310 if ((q - buf) < sizeof(buf) - 1) | |
1311 *q++ = c; | |
1312 c = url_fgetc(f); | |
1313 } | |
1314 *q = '\0'; | |
1315 //printf("URL='%s'\n", buf); | |
1316 /* try to open the media file */ | |
1317 if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0) | |
1318 break; | |
1319 } | |
1320 *ic_ptr = ic; | |
1321 if (!ic) | |
1322 return AVERROR_IO; | |
1323 else | |
1324 return 0; | |
1325 } | |
1326 | |
1327 AVInputFormat redir_demux = { | |
1328 "redir", | |
1329 "Redirector format", | |
1330 0, | |
1331 redir_probe, | |
1332 NULL, | |
1333 NULL, | |
1334 NULL, | |
1335 }; | |
1336 | |
1337 int rtsp_init(void) | |
1338 { | |
1339 av_register_input_format(&rtsp_demux); | |
1340 av_register_input_format(&redir_demux); | |
1341 av_register_input_format(&sdp_demux); | |
1342 return 0; | |
1343 } |