Mercurial > libavformat.hg
annotate rtsp.c @ 355:46029c682234 libavformat
seeking stuff
adaptively change middle position selection algo for seeking, this avoids some ugly worstcases of the interpolated variant
avoid backward search for mpeg where possible, its 17 times slower then forward according to my benchmark
author | michael |
---|---|
date | Sat, 17 Jan 2004 20:26:44 +0000 |
parents | d58c8859ff8c |
children | 845f9de2c883 |
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 */ | |
342 url_split(proto, sizeof(proto), NULL, 0, NULL, NULL, 0, p); | |
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 | |
179 | 565 /* skip a RTP/TCP interleaved packet */ |
566 static void rtsp_skip_packet(AVFormatContext *s) | |
567 { | |
568 RTSPState *rt = s->priv_data; | |
569 int ret, len, len1; | |
570 uint8_t buf[1024]; | |
571 | |
572 ret = url_read(rt->rtsp_hd, buf, 3); | |
573 if (ret != 3) | |
574 return; | |
575 len = (buf[1] << 8) | buf[2]; | |
576 #ifdef DEBUG | |
577 printf("skipping RTP packet len=%d\n", len); | |
578 #endif | |
579 /* skip payload */ | |
580 while (len > 0) { | |
581 len1 = len; | |
582 if (len1 > sizeof(buf)) | |
583 len1 = sizeof(buf); | |
584 ret = url_read(rt->rtsp_hd, buf, len1); | |
585 if (ret != len1) | |
586 return; | |
587 len -= len1; | |
588 } | |
589 } | |
0 | 590 |
591 static void rtsp_send_cmd(AVFormatContext *s, | |
592 const char *cmd, RTSPHeader *reply, | |
593 unsigned char **content_ptr) | |
594 { | |
595 RTSPState *rt = s->priv_data; | |
596 char buf[4096], buf1[1024], *q; | |
597 unsigned char ch; | |
598 const char *p; | |
599 int content_length, line_count; | |
600 unsigned char *content = NULL; | |
601 | |
602 memset(reply, 0, sizeof(RTSPHeader)); | |
603 | |
604 rt->seq++; | |
605 pstrcpy(buf, sizeof(buf), cmd); | |
172 | 606 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq); |
0 | 607 pstrcat(buf, sizeof(buf), buf1); |
608 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) { | |
172 | 609 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id); |
0 | 610 pstrcat(buf, sizeof(buf), buf1); |
611 } | |
172 | 612 pstrcat(buf, sizeof(buf), "\r\n"); |
0 | 613 #ifdef DEBUG |
614 printf("Sending:\n%s--\n", buf); | |
615 #endif | |
616 url_write(rt->rtsp_hd, buf, strlen(buf)); | |
617 | |
618 /* parse reply (XXX: use buffers) */ | |
619 line_count = 0; | |
620 rt->last_reply[0] = '\0'; | |
621 for(;;) { | |
622 q = buf; | |
623 for(;;) { | |
179 | 624 if (url_read(rt->rtsp_hd, &ch, 1) != 1) |
0 | 625 break; |
626 if (ch == '\n') | |
627 break; | |
179 | 628 if (ch == '$') { |
629 /* XXX: only parse it if first char on line ? */ | |
630 rtsp_skip_packet(s); | |
631 } else if (ch != '\r') { | |
0 | 632 if ((q - buf) < sizeof(buf) - 1) |
633 *q++ = ch; | |
634 } | |
635 } | |
636 *q = '\0'; | |
637 #ifdef DEBUG | |
638 printf("line='%s'\n", buf); | |
639 #endif | |
640 /* test if last line */ | |
641 if (buf[0] == '\0') | |
642 break; | |
643 p = buf; | |
644 if (line_count == 0) { | |
645 /* get reply code */ | |
646 get_word(buf1, sizeof(buf1), &p); | |
647 get_word(buf1, sizeof(buf1), &p); | |
648 reply->status_code = atoi(buf1); | |
649 } else { | |
650 rtsp_parse_line(reply, p); | |
651 pstrcat(rt->last_reply, sizeof(rt->last_reply), p); | |
652 pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n"); | |
653 } | |
654 line_count++; | |
655 } | |
656 | |
657 if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') | |
658 pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id); | |
659 | |
660 content_length = reply->content_length; | |
661 if (content_length > 0) { | |
662 /* leave some room for a trailing '\0' (useful for simple parsing) */ | |
663 content = av_malloc(content_length + 1); | |
664 url_read(rt->rtsp_hd, content, content_length); | |
665 content[content_length] = '\0'; | |
666 } | |
667 if (content_ptr) | |
668 *content_ptr = content; | |
669 } | |
670 | |
671 /* useful for modules: set RTSP callback function */ | |
672 | |
673 void rtsp_set_callback(FFRTSPCallback *rtsp_cb) | |
674 { | |
675 ff_rtsp_callback = rtsp_cb; | |
676 } | |
677 | |
678 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
679 /* 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
|
680 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
|
681 { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
682 int i; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
683 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
|
684 |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
685 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
|
686 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
|
687 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
|
688 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
|
689 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
|
690 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
|
691 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
|
692 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
693 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
|
694 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
695 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
|
696 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
697 |
0 | 698 static int rtsp_read_header(AVFormatContext *s, |
699 AVFormatParameters *ap) | |
700 { | |
701 RTSPState *rt = s->priv_data; | |
702 char host[1024], path[1024], tcpname[1024], cmd[2048]; | |
703 URLContext *rtsp_hd; | |
704 int port, i, ret, err; | |
705 RTSPHeader reply1, *reply = &reply1; | |
706 unsigned char *content = NULL; | |
707 RTSPStream *rtsp_st; | |
708 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
|
709 AVStream *st; |
0 | 710 |
711 /* extract hostname and port */ | |
712 url_split(NULL, 0, | |
713 host, sizeof(host), &port, path, sizeof(path), s->filename); | |
714 if (port < 0) | |
715 port = RTSP_DEFAULT_PORT; | |
716 | |
717 /* open the tcp connexion */ | |
718 snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port); | |
719 if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) | |
720 return AVERROR_IO; | |
721 rt->rtsp_hd = rtsp_hd; | |
722 rt->seq = 0; | |
723 | |
724 /* describe the stream */ | |
725 snprintf(cmd, sizeof(cmd), | |
172 | 726 "DESCRIBE %s RTSP/1.0\r\n" |
727 "Accept: application/sdp\r\n", | |
0 | 728 s->filename); |
729 rtsp_send_cmd(s, cmd, reply, &content); | |
730 if (!content) { | |
731 err = AVERROR_INVALIDDATA; | |
732 goto fail; | |
733 } | |
734 if (reply->status_code != RTSP_STATUS_OK) { | |
735 err = AVERROR_INVALIDDATA; | |
736 goto fail; | |
737 } | |
738 | |
739 /* now we got the SDP description, we parse it */ | |
740 ret = sdp_parse(s, (const char *)content); | |
741 av_freep(&content); | |
742 if (ret < 0) { | |
743 err = AVERROR_INVALIDDATA; | |
744 goto fail; | |
745 } | |
746 | |
747 protocol_mask = rtsp_default_protocols; | |
748 | |
749 /* for each stream, make the setup request */ | |
750 /* XXX: we assume the same server is used for the control of each | |
751 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
|
752 for(i=0;i<rt->nb_rtsp_streams;i++) { |
0 | 753 char transport[2048]; |
754 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
755 rtsp_st = rt->rtsp_streams[i]; |
0 | 756 |
757 /* compute available transports */ | |
758 transport[0] = '\0'; | |
759 | |
760 /* RTP/UDP */ | |
761 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) { | |
762 char buf[256]; | |
763 int j; | |
764 | |
765 /* first try in specified port range */ | |
766 if (rtsp_rtp_port_min != 0) { | |
767 for(j=rtsp_rtp_port_min;j<=rtsp_rtp_port_max;j++) { | |
768 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
|
769 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) |
0 | 770 goto rtp_opened; |
771 } | |
772 } | |
773 | |
774 /* 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
|
775 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
|
776 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
|
777 goto fail; |
0 | 778 } |
779 | |
780 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
|
781 port = rtp_get_local_port(rtsp_st->rtp_handle); |
0 | 782 if (transport[0] != '\0') |
783 pstrcat(transport, sizeof(transport), ","); | |
784 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, | |
785 "RTP/AVP/UDP;unicast;client_port=%d-%d", | |
786 port, port + 1); | |
787 } | |
788 | |
789 /* RTP/TCP */ | |
790 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) { | |
791 if (transport[0] != '\0') | |
792 pstrcat(transport, sizeof(transport), ","); | |
793 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, | |
794 "RTP/AVP/TCP"); | |
795 } | |
796 | |
797 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) { | |
798 if (transport[0] != '\0') | |
799 pstrcat(transport, sizeof(transport), ","); | |
800 snprintf(transport + strlen(transport), | |
801 sizeof(transport) - strlen(transport) - 1, | |
802 "RTP/AVP/UDP;multicast"); | |
803 } | |
804 snprintf(cmd, sizeof(cmd), | |
172 | 805 "SETUP %s RTSP/1.0\r\n" |
806 "Transport: %s\r\n", | |
0 | 807 rtsp_st->control_url, transport); |
808 rtsp_send_cmd(s, cmd, reply, NULL); | |
809 if (reply->status_code != RTSP_STATUS_OK || | |
810 reply->nb_transports != 1) { | |
811 err = AVERROR_INVALIDDATA; | |
812 goto fail; | |
813 } | |
814 | |
815 /* XXX: same protocol for all streams is required */ | |
816 if (i > 0) { | |
817 if (reply->transports[0].protocol != rt->protocol) { | |
818 err = AVERROR_INVALIDDATA; | |
819 goto fail; | |
820 } | |
821 } else { | |
822 rt->protocol = reply->transports[0].protocol; | |
823 } | |
824 | |
825 /* close RTP connection if not choosen */ | |
826 if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP && | |
827 (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
|
828 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
|
829 rtsp_st->rtp_handle = NULL; |
0 | 830 } |
831 | |
832 switch(reply->transports[0].protocol) { | |
833 case RTSP_PROTOCOL_RTP_TCP: | |
834 rtsp_st->interleaved_min = reply->transports[0].interleaved_min; | |
835 rtsp_st->interleaved_max = reply->transports[0].interleaved_max; | |
836 break; | |
837 | |
838 case RTSP_PROTOCOL_RTP_UDP: | |
839 { | |
840 char url[1024]; | |
841 | |
842 /* XXX: also use address if specified */ | |
843 snprintf(url, sizeof(url), "rtp://%s:%d", | |
844 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
|
845 if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { |
0 | 846 err = AVERROR_INVALIDDATA; |
847 goto fail; | |
848 } | |
849 } | |
850 break; | |
851 case RTSP_PROTOCOL_RTP_UDP_MULTICAST: | |
852 { | |
853 char url[1024]; | |
854 int ttl; | |
855 | |
856 ttl = reply->transports[0].ttl; | |
857 if (!ttl) | |
858 ttl = 16; | |
859 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", | |
860 host, | |
861 reply->transports[0].server_port_min, | |
862 ttl); | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
863 if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) { |
0 | 864 err = AVERROR_INVALIDDATA; |
865 goto fail; | |
866 } | |
867 } | |
868 break; | |
869 } | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
870 /* 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
|
871 st = NULL; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
872 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
|
873 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
|
874 if (!st) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
875 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
|
876 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
|
877 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
|
878 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
|
879 goto fail; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
880 } |
0 | 881 } |
882 | |
883 /* use callback if available to extend setup */ | |
884 if (ff_rtsp_callback) { | |
885 if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, | |
886 NULL, 0, rt->last_reply) < 0) { | |
887 err = AVERROR_INVALIDDATA; | |
888 goto fail; | |
889 } | |
890 } | |
891 | |
892 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
893 rt->state = RTSP_STATE_IDLE; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
894 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
|
895 zero */ |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
896 if (ap && ap->initial_pause) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
897 /* do not start immediately */ |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
898 } else { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
899 if (rtsp_read_play(s) < 0) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
900 err = AVERROR_INVALIDDATA; |
0 | 901 goto fail; |
902 } | |
903 } | |
904 return 0; | |
905 fail: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
906 rtsp_close_streams(rt); |
0 | 907 av_freep(&content); |
908 url_close(rt->rtsp_hd); | |
909 return err; | |
910 } | |
911 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
912 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
|
913 uint8_t *buf, int buf_size) |
0 | 914 { |
915 RTSPState *rt = s->priv_data; | |
172 | 916 int id, len, i, ret; |
0 | 917 RTSPStream *rtsp_st; |
918 | |
172 | 919 #ifdef DEBUG_RTP_TCP |
920 printf("tcp_read_packet:\n"); | |
921 #endif | |
0 | 922 redo: |
923 for(;;) { | |
172 | 924 ret = url_read(rt->rtsp_hd, buf, 1); |
925 #ifdef DEBUG_RTP_TCP | |
926 printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]); | |
927 #endif | |
928 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
|
929 return -1; |
172 | 930 if (buf[0] == '$') |
0 | 931 break; |
932 } | |
172 | 933 ret = url_read(rt->rtsp_hd, buf, 3); |
934 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
|
935 return -1; |
172 | 936 id = buf[0]; |
937 len = (buf[1] << 8) | buf[2]; | |
938 #ifdef DEBUG_RTP_TCP | |
939 printf("id=%d len=%d\n", id, len); | |
940 #endif | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
941 if (len > buf_size || len < 12) |
0 | 942 goto redo; |
943 /* get the data */ | |
172 | 944 ret = url_read(rt->rtsp_hd, buf, len); |
945 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
|
946 return -1; |
172 | 947 |
0 | 948 /* 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
|
949 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
|
950 rtsp_st = rt->rtsp_streams[i]; |
172 | 951 if (id >= rtsp_st->interleaved_min && |
952 id <= rtsp_st->interleaved_max) | |
0 | 953 goto found; |
954 } | |
955 goto redo; | |
956 found: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
957 *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
|
958 return len; |
0 | 959 } |
960 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
961 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
|
962 uint8_t *buf, int buf_size) |
0 | 963 { |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
964 RTSPState *rt = s->priv_data; |
0 | 965 RTSPStream *rtsp_st; |
966 fd_set rfds; | |
967 int fd1, fd2, fd_max, n, i, ret; | |
968 struct timeval tv; | |
969 | |
970 for(;;) { | |
179 | 971 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
|
972 return -1; |
0 | 973 FD_ZERO(&rfds); |
974 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
|
975 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
|
976 rtsp_st = rt->rtsp_streams[i]; |
0 | 977 /* 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
|
978 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2); |
0 | 979 if (fd1 > fd_max) |
980 fd_max = fd1; | |
981 FD_SET(fd1, &rfds); | |
982 } | |
983 tv.tv_sec = 0; | |
179 | 984 tv.tv_usec = 100 * 1000; |
0 | 985 n = select(fd_max + 1, &rfds, NULL, NULL, &tv); |
986 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
|
987 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
|
988 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
|
989 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2); |
0 | 990 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
|
991 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
|
992 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
|
993 *prtsp_st = rtsp_st; |
0 | 994 return ret; |
995 } | |
996 } | |
997 } | |
998 } | |
999 } | |
1000 } | |
1001 | |
1002 static int rtsp_read_packet(AVFormatContext *s, | |
1003 AVPacket *pkt) | |
1004 { | |
1005 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
|
1006 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
|
1007 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
|
1008 uint8_t buf[RTP_MAX_PACKET_LENGTH]; |
0 | 1009 |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1010 /* 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
|
1011 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
|
1012 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
|
1013 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
|
1014 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
|
1015 return 0; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1016 } 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
|
1017 return 0; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1018 } else { |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1019 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
|
1020 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1021 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1022 |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1023 /* 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
|
1024 redo: |
0 | 1025 switch(rt->protocol) { |
1026 default: | |
1027 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
|
1028 len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf)); |
0 | 1029 break; |
1030 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
|
1031 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
|
1032 len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf)); |
0 | 1033 break; |
1034 } | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1035 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
|
1036 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
|
1037 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
|
1038 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
|
1039 goto redo; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1040 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
|
1041 /* 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
|
1042 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
|
1043 } |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1044 return 0; |
0 | 1045 } |
1046 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1047 static int rtsp_read_play(AVFormatContext *s) |
179 | 1048 { |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1049 RTSPState *rt = s->priv_data; |
179 | 1050 RTSPHeader reply1, *reply = &reply1; |
1051 char cmd[1024]; | |
1052 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1053 printf("hello state=%d\n", rt->state); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1054 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1055 if (rt->state == RTSP_STATE_PAUSED) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1056 snprintf(cmd, sizeof(cmd), |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1057 "PLAY %s RTSP/1.0\r\n", |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1058 s->filename); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1059 } else { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1060 snprintf(cmd, sizeof(cmd), |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1061 "PLAY %s RTSP/1.0\r\n" |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1062 "Range: npt=%0.3f-\r\n", |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1063 s->filename, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1064 (double)rt->seek_timestamp / AV_TIME_BASE); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1065 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1066 rtsp_send_cmd(s, cmd, reply, NULL); |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1067 if (reply->status_code != RTSP_STATUS_OK) { |
179 | 1068 return -1; |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1069 } else { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1070 rt->state = RTSP_STATE_PLAYING; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1071 return 0; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1072 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1073 } |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1074 |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1075 /* pause the stream */ |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1076 static int rtsp_read_pause(AVFormatContext *s) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1077 { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1078 RTSPState *rt = s->priv_data; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1079 RTSPHeader reply1, *reply = &reply1; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1080 char cmd[1024]; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1081 |
179 | 1082 rt = s->priv_data; |
1083 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1084 if (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 |
179 | 1087 snprintf(cmd, sizeof(cmd), |
1088 "PAUSE %s RTSP/1.0\r\n", | |
1089 s->filename); | |
1090 rtsp_send_cmd(s, cmd, reply, NULL); | |
1091 if (reply->status_code != RTSP_STATUS_OK) { | |
1092 return -1; | |
1093 } else { | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1094 rt->state = RTSP_STATE_PAUSED; |
179 | 1095 return 0; |
1096 } | |
1097 } | |
1098 | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1099 static int rtsp_read_seek(AVFormatContext *s, int stream_index, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1100 int64_t timestamp) |
179 | 1101 { |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1102 RTSPState *rt = s->priv_data; |
179 | 1103 |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1104 rt->seek_timestamp = timestamp; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1105 switch(rt->state) { |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1106 default: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1107 case RTSP_STATE_IDLE: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1108 break; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1109 case RTSP_STATE_PLAYING: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1110 if (rtsp_read_play(s) != 0) |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1111 return -1; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1112 break; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1113 case RTSP_STATE_PAUSED: |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1114 rt->state = RTSP_STATE_IDLE; |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1115 break; |
179 | 1116 } |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1117 return 0; |
179 | 1118 } |
1119 | |
0 | 1120 static int rtsp_read_close(AVFormatContext *s) |
1121 { | |
1122 RTSPState *rt = s->priv_data; | |
1123 RTSPHeader reply1, *reply = &reply1; | |
1124 char cmd[1024]; | |
1125 | |
172 | 1126 #if 0 |
0 | 1127 /* NOTE: it is valid to flush the buffer here */ |
1128 if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) { | |
1129 url_fclose(&rt->rtsp_gb); | |
1130 } | |
172 | 1131 #endif |
0 | 1132 snprintf(cmd, sizeof(cmd), |
172 | 1133 "TEARDOWN %s RTSP/1.0\r\n", |
0 | 1134 s->filename); |
1135 rtsp_send_cmd(s, cmd, reply, NULL); | |
1136 | |
1137 if (ff_rtsp_callback) { | |
1138 ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id, | |
1139 NULL, 0, NULL); | |
1140 } | |
1141 | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1142 rtsp_close_streams(rt); |
0 | 1143 url_close(rt->rtsp_hd); |
1144 return 0; | |
1145 } | |
1146 | |
179 | 1147 AVInputFormat rtsp_demux = { |
0 | 1148 "rtsp", |
1149 "RTSP input format", | |
1150 sizeof(RTSPState), | |
1151 rtsp_probe, | |
1152 rtsp_read_header, | |
1153 rtsp_read_packet, | |
1154 rtsp_read_close, | |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1155 rtsp_read_seek, |
0 | 1156 .flags = AVFMT_NOFILE, |
304
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1157 .read_play = rtsp_read_play, |
d58c8859ff8c
initial seek support - more generic play/pause support
bellard
parents:
294
diff
changeset
|
1158 .read_pause = rtsp_read_pause, |
0 | 1159 }; |
1160 | |
1161 static int sdp_probe(AVProbeData *p1) | |
1162 { | |
1163 const char *p; | |
1164 | |
1165 /* we look for a line beginning "c=IN IP4" */ | |
1166 p = p1->buf; | |
1167 while (*p != '\0') { | |
1168 if (strstart(p, "c=IN IP4", NULL)) | |
1169 return AVPROBE_SCORE_MAX / 2; | |
1170 p = strchr(p, '\n'); | |
1171 if (!p) | |
1172 break; | |
1173 p++; | |
1174 if (*p == '\r') | |
1175 p++; | |
1176 } | |
1177 return 0; | |
1178 } | |
1179 | |
1180 #define SDP_MAX_SIZE 8192 | |
1181 | |
1182 static int sdp_read_header(AVFormatContext *s, | |
1183 AVFormatParameters *ap) | |
1184 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1185 RTSPState *rt = s->priv_data; |
0 | 1186 RTSPStream *rtsp_st; |
1187 int size, i, err; | |
1188 char *content; | |
1189 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
|
1190 AVStream *st; |
0 | 1191 |
1192 /* read the whole sdp file */ | |
1193 /* XXX: better loading */ | |
1194 content = av_malloc(SDP_MAX_SIZE); | |
1195 size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1); | |
1196 if (size <= 0) { | |
1197 av_free(content); | |
1198 return AVERROR_INVALIDDATA; | |
1199 } | |
1200 content[size] ='\0'; | |
1201 | |
1202 sdp_parse(s, content); | |
1203 av_free(content); | |
1204 | |
1205 /* 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
|
1206 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
|
1207 rtsp_st = rt->rtsp_streams[i]; |
0 | 1208 |
1209 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", | |
1210 inet_ntoa(rtsp_st->sdp_ip), | |
1211 rtsp_st->sdp_port, | |
1212 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
|
1213 if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) { |
0 | 1214 err = AVERROR_INVALIDDATA; |
1215 goto fail; | |
1216 } | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1217 /* 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
|
1218 st = NULL; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1219 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
|
1220 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
|
1221 if (!st) |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1222 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
|
1223 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
|
1224 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
|
1225 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
|
1226 goto fail; |
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1227 } |
0 | 1228 } |
1229 return 0; | |
1230 fail: | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1231 rtsp_close_streams(rt); |
0 | 1232 return err; |
1233 } | |
1234 | |
1235 static int sdp_read_packet(AVFormatContext *s, | |
1236 AVPacket *pkt) | |
1237 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1238 return rtsp_read_packet(s, pkt); |
0 | 1239 } |
1240 | |
1241 static int sdp_read_close(AVFormatContext *s) | |
1242 { | |
294
6091b76cfc2a
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
bellard
parents:
229
diff
changeset
|
1243 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
|
1244 rtsp_close_streams(rt); |
0 | 1245 return 0; |
1246 } | |
1247 | |
1248 | |
1249 static AVInputFormat sdp_demux = { | |
1250 "sdp", | |
1251 "SDP", | |
1252 sizeof(RTSPState), | |
1253 sdp_probe, | |
1254 sdp_read_header, | |
1255 sdp_read_packet, | |
1256 sdp_read_close, | |
1257 }; | |
1258 | |
1259 | |
1260 /* dummy redirector format (used directly in av_open_input_file now) */ | |
1261 static int redir_probe(AVProbeData *pd) | |
1262 { | |
1263 const char *p; | |
1264 p = pd->buf; | |
1265 while (redir_isspace(*p)) | |
1266 p++; | |
1267 if (strstart(p, "http://", NULL) || | |
1268 strstart(p, "rtsp://", NULL)) | |
1269 return AVPROBE_SCORE_MAX; | |
1270 return 0; | |
1271 } | |
1272 | |
1273 /* called from utils.c */ | |
1274 int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f) | |
1275 { | |
1276 char buf[4096], *q; | |
1277 int c; | |
1278 AVFormatContext *ic = NULL; | |
1279 | |
1280 /* parse each URL and try to open it */ | |
1281 c = url_fgetc(f); | |
1282 while (c != URL_EOF) { | |
1283 /* skip spaces */ | |
1284 for(;;) { | |
1285 if (!redir_isspace(c)) | |
1286 break; | |
1287 c = url_fgetc(f); | |
1288 } | |
1289 if (c == URL_EOF) | |
1290 break; | |
1291 /* record url */ | |
1292 q = buf; | |
1293 for(;;) { | |
1294 if (c == URL_EOF || redir_isspace(c)) | |
1295 break; | |
1296 if ((q - buf) < sizeof(buf) - 1) | |
1297 *q++ = c; | |
1298 c = url_fgetc(f); | |
1299 } | |
1300 *q = '\0'; | |
1301 //printf("URL='%s'\n", buf); | |
1302 /* try to open the media file */ | |
1303 if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0) | |
1304 break; | |
1305 } | |
1306 *ic_ptr = ic; | |
1307 if (!ic) | |
1308 return AVERROR_IO; | |
1309 else | |
1310 return 0; | |
1311 } | |
1312 | |
1313 AVInputFormat redir_demux = { | |
1314 "redir", | |
1315 "Redirector format", | |
1316 0, | |
1317 redir_probe, | |
1318 NULL, | |
1319 NULL, | |
1320 NULL, | |
1321 }; | |
1322 | |
1323 int rtsp_init(void) | |
1324 { | |
1325 av_register_input_format(&rtsp_demux); | |
1326 av_register_input_format(&redir_demux); | |
1327 av_register_input_format(&sdp_demux); | |
1328 return 0; | |
1329 } |