make AVFMT_NOHEADER flag dynamic - added av_open_input_stream()
[libav.git] / libavformat / rtsp.c
CommitLineData
1617ad97 1/*
93ced3e8 2 * RTSP/SDP client
1617ad97
FB
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
438fcb75 21#include <unistd.h> /* for select() prototype */
1617ad97 22#include <sys/time.h>
b8a78f41 23#include <netinet/in.h>
1617ad97 24#include <sys/socket.h>
9ddd71fc
FR
25#ifndef __BEOS__
26# include <arpa/inet.h>
27#else
28# include "barpainet.h"
29#endif
1617ad97
FB
30
31//#define DEBUG
b6892136 32//#define DEBUG_RTP_TCP
1617ad97
FB
33
34typedef struct RTSPState {
35 URLContext *rtsp_hd; /* RTSP TCP connexion handle */
b6892136
FB
36 /* XXX: currently we use unbuffered input */
37 // ByteIOContext rtsp_gb;
1617ad97
FB
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
44typedef struct RTSPStream {
45 AVFormatContext *ic;
46 int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */
93ced3e8
FB
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 */
1617ad97
FB
53} RTSPStream;
54
1617ad97
FB
55/* XXX: currently, the only way to change the protocols consists in
56 changing this variable */
b6892136 57#if 1
1617ad97 58int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST);
b6892136
FB
59#else
60/* try it if a proxy is used */
61int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
62#endif
1617ad97 63
85fb7b34
FB
64/* if non zero, then set a range for RTP ports */
65int rtsp_rtp_port_min = 0;
66int rtsp_rtp_port_max = 0;
67
1617ad97
FB
68FFRTSPCallback *ff_rtsp_callback = NULL;
69
70static int rtsp_probe(AVProbeData *p)
71{
72 if (strstart(p->filename, "rtsp:", NULL))
73 return AVPROBE_SCORE_MAX;
74 return 0;
75}
76
77static int redir_isspace(int c)
78{
79 return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
80}
81
82static 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
91static 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
110static 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
93ced3e8
FB
128/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
129 params>] */
130static 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 */
145static 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
173static 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
212typedef struct SDPParseState {
213 /* SDP only */
214 struct in_addr default_ip;
215 int default_ttl;
216} SDPParseState;
217
218static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
1617ad97
FB
219 int letter, const char *buf)
220{
221 char buf1[64], st_type[64];
222 const char *p;
93ced3e8 223 int codec_type, payload_type, i;
1617ad97
FB
224 AVStream *st;
225 RTSPStream *rtsp_st;
93ced3e8
FB
226 struct in_addr sdp_ip;
227 int ttl;
228
1617ad97
FB
229#ifdef DEBUG
230 printf("sdp: %c='%s'\n", letter, buf);
231#endif
232
233 p = buf;
234 switch(letter) {
93ced3e8
FB
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;
1617ad97
FB
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 }
1617ad97
FB
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;
93ced3e8
FB
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
1617ad97
FB
306 /* put a default control url */
307 pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename);
1617ad97
FB
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 }
93ced3e8
FB
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 }
1617ad97
FB
347 }
348 break;
349 }
350}
351
5c91a675 352static int sdp_parse(AVFormatContext *s, const char *content)
1617ad97
FB
353{
354 const char *p;
355 int letter;
356 char buf[1024], *q;
93ced3e8
FB
357 SDPParseState sdp_parse_state, *s1 = &sdp_parse_state;
358
359 memset(s1, 0, sizeof(SDPParseState));
1617ad97
FB
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;
b6892136 372 while (*p != '\n' && *p != '\r' && *p != '\0') {
1617ad97
FB
373 if ((q - buf) < sizeof(buf) - 1)
374 *q++ = *p;
375 p++;
376 }
377 *q = '\0';
93ced3e8 378 sdp_parse_line(s, s1, letter, buf);
1617ad97
FB
379 next_line:
380 while (*p != '\n' && *p != '\0')
381 p++;
382 if (*p == '\n')
383 p++;
384 }
385 return 0;
386}
387
388static 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 */
409static 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 == '/') {
b6892136 434 p++;
1617ad97
FB
435 get_word_sep(lower_transport, sizeof(lower_transport),
436 ";,", &p);
437 }
b6892136 438 if (!strcasecmp(lower_transport, "TCP"))
1617ad97
FB
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
501void 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
b7b8fc34
FB
518/* skip a RTP/TCP interleaved packet */
519static 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}
1617ad97
FB
543
544static 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);
b6892136 559 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
1617ad97
FB
560 pstrcat(buf, sizeof(buf), buf1);
561 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
b6892136 562 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
1617ad97
FB
563 pstrcat(buf, sizeof(buf), buf1);
564 }
b6892136 565 pstrcat(buf, sizeof(buf), "\r\n");
1617ad97
FB
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(;;) {
b7b8fc34 577 if (url_read(rt->rtsp_hd, &ch, 1) != 1)
1617ad97
FB
578 break;
579 if (ch == '\n')
580 break;
b7b8fc34
FB
581 if (ch == '$') {
582 /* XXX: only parse it if first char on line ? */
583 rtsp_skip_packet(s);
584 } else if (ch != '\r') {
1617ad97
FB
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
626void rtsp_set_callback(FFRTSPCallback *rtsp_cb)
627{
628 ff_rtsp_callback = rtsp_cb;
629}
630
631
632static 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
1617ad97
FB
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),
b6892136
FB
660 "DESCRIBE %s RTSP/1.0\r\n"
661 "Accept: application/sdp\r\n",
1617ad97
FB
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++) {
1617ad97 687 char transport[2048];
85fb7b34 688 AVInputFormat *fmt;
1617ad97
FB
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)) {
85fb7b34
FB
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 }
1617ad97 709 }
85fb7b34
FB
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:
1617ad97
FB
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 }
1617ad97 742 snprintf(cmd, sizeof(cmd),
b6892136
FB
743 "SETUP %s RTSP/1.0\r\n"
744 "Transport: %s\r\n",
1617ad97
FB
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),
b6892136
FB
827 "PLAY %s RTSP/1.0\r\n"
828 "Range: npt=0-\r\n",
1617ad97
FB
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
b6892136 836#if 0
1617ad97
FB
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 }
b6892136 844#endif
1617ad97
FB
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
862static int tcp_read_packet(AVFormatContext *s,
863 AVPacket *pkt)
864{
865 RTSPState *rt = s->priv_data;
b6892136 866 int id, len, i, ret;
1617ad97
FB
867 AVStream *st;
868 RTSPStream *rtsp_st;
b6892136 869 uint8_t buf[RTP_MAX_PACKET_LENGTH];
1617ad97 870
b6892136
FB
871#ifdef DEBUG_RTP_TCP
872 printf("tcp_read_packet:\n");
873#endif
1617ad97
FB
874 redo:
875 for(;;) {
b6892136
FB
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)
1617ad97 881 return AVERROR_IO;
b6892136 882 if (buf[0] == '$')
1617ad97
FB
883 break;
884 }
b6892136
FB
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
1617ad97
FB
893 if (len > RTP_MAX_PACKET_LENGTH || len < 12)
894 goto redo;
895 /* get the data */
b6892136
FB
896 ret = url_read(rt->rtsp_hd, buf, len);
897 if (ret != len)
898 return AVERROR_IO;
899
1617ad97
FB
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;
b6892136
FB
904 if (id >= rtsp_st->interleaved_min &&
905 id <= rtsp_st->interleaved_max)
1617ad97
FB
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 */
918static 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(;;) {
b7b8fc34 930 if (url_interrupt_cb())
1617ad97
FB
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;
b7b8fc34 946 tv.tv_usec = 100 * 1000;
1617ad97
FB
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
967static 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
b7b8fc34
FB
985/* pause the stream */
986int 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 */
1009int 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
1617ad97
FB
1031static 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
b6892136 1040#if 0
1617ad97
FB
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 }
b6892136 1045#endif
1617ad97 1046 snprintf(cmd, sizeof(cmd),
b6892136 1047 "TEARDOWN %s RTSP/1.0\r\n",
1617ad97
FB
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
b7b8fc34 1069AVInputFormat rtsp_demux = {
1617ad97
FB
1070 "rtsp",
1071 "RTSP input format",
1072 sizeof(RTSPState),
1073 rtsp_probe,
1074 rtsp_read_header,
1075 rtsp_read_packet,
1076 rtsp_read_close,
bb76a117 1077 .flags = AVFMT_NOFILE,
1617ad97
FB
1078};
1079
cb1fdc61 1080static int sdp_probe(AVProbeData *p1)
93ced3e8 1081{
cb1fdc61
FB
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 }
93ced3e8
FB
1096 return 0;
1097}
1098
1099#define SDP_MAX_SIZE 8192
1100
1101static 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
1151static int sdp_read_packet(AVFormatContext *s,
1152 AVPacket *pkt)
1153{
1154 return udp_read_packet(s, pkt);
1155}
1156
1157static 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
1176static 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
1617ad97
FB
1187/* dummy redirector format (used directly in av_open_input_file now) */
1188static 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 */
1201int 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
1240AVInputFormat redir_demux = {
1241 "redir",
1242 "Redirector format",
1243 0,
1244 redir_probe,
1245 NULL,
1246 NULL,
1247 NULL,
1248};
1249
1250int rtsp_init(void)
1251{
1252 av_register_input_format(&rtsp_demux);
1253 av_register_input_format(&redir_demux);
93ced3e8 1254 av_register_input_format(&sdp_demux);
1617ad97
FB
1255 return 0;
1256}