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