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