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