new optimized eval method, by seperating parsing and runtime
[libav.git] / libavformat / rtsp.c
CommitLineData
1617ad97 1/*
93ced3e8 2 * RTSP/SDP client
1617ad97
FB
3 * Copyright (c) 2002 Fabrice Bellard.
4 *
b78e7197
DB
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
1617ad97
FB
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
b78e7197 10 * version 2.1 of the License, or (at your option) any later version.
1617ad97 11 *
b78e7197 12 * FFmpeg is distributed in the hope that it will be useful,
1617ad97
FB
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
b78e7197 18 * License along with FFmpeg; if not, write to the Free Software
5509bffa 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1617ad97
FB
20 */
21#include "avformat.h"
22
438fcb75 23#include <unistd.h> /* for select() prototype */
1617ad97 24#include <sys/time.h>
b8a78f41 25#include <netinet/in.h>
1617ad97 26#include <sys/socket.h>
9ddd71fc
FR
27#ifndef __BEOS__
28# include <arpa/inet.h>
29#else
30# include "barpainet.h"
31#endif
1617ad97 32
4934884a
RM
33#include "rtp_internal.h"
34
1617ad97 35//#define DEBUG
b6892136 36//#define DEBUG_RTP_TCP
1617ad97 37
ff762d6e
FB
38enum RTSPClientState {
39 RTSP_STATE_IDLE,
40 RTSP_STATE_PLAYING,
41 RTSP_STATE_PAUSED,
42};
43
1617ad97
FB
44typedef struct RTSPState {
45 URLContext *rtsp_hd; /* RTSP TCP connexion handle */
8b1ab7bf
FB
46 int nb_rtsp_streams;
47 struct RTSPStream **rtsp_streams;
115329f1 48
ff762d6e
FB
49 enum RTSPClientState state;
50 int64_t seek_timestamp;
115329f1 51
b6892136
FB
52 /* XXX: currently we use unbuffered input */
53 // ByteIOContext rtsp_gb;
1617ad97
FB
54 int seq; /* RTSP command sequence number */
55 char session_id[512];
56 enum RTSPProtocol protocol;
57 char last_reply[2048]; /* XXX: allocate ? */
8b1ab7bf 58 RTPDemuxContext *cur_rtp;
1617ad97
FB
59} RTSPState;
60
61typedef struct RTSPStream {
8b1ab7bf
FB
62 URLContext *rtp_handle; /* RTP stream handle */
63 RTPDemuxContext *rtp_ctx; /* RTP parse context */
115329f1 64
8b1ab7bf 65 int stream_index; /* corresponding stream index, if any. -1 if none (MPEG2TS case) */
1617ad97 66 int interleaved_min, interleaved_max; /* interleave ids, if TCP transport */
93ced3e8
FB
67 char control_url[1024]; /* url for this stream (from SDP) */
68
69 int sdp_port; /* port (from SDP content - not used in RTSP) */
70 struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */
71 int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */
72 int sdp_payload_type; /* payload type - only used in SDP */
d1ccf0e0 73 rtp_payload_data_t rtp_payload_data; /* rtp payload parsing infos from SDP */
4934884a
RM
74
75 RTPDynamicProtocolHandler *dynamic_handler; ///< Only valid if it's a dynamic protocol. (This is the handler structure)
76 void *dynamic_protocol_context; ///< Only valid if it's a dynamic protocol. (This is any private data associated with the dynamic protocol)
1617ad97
FB
77} RTSPStream;
78
ff762d6e
FB
79static int rtsp_read_play(AVFormatContext *s);
80
1617ad97
FB
81/* XXX: currently, the only way to change the protocols consists in
82 changing this variable */
1617ad97 83
d1ccf0e0 84int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_UDP);
85fb7b34 85
1617ad97
FB
86FFRTSPCallback *ff_rtsp_callback = NULL;
87
88static int rtsp_probe(AVProbeData *p)
89{
90 if (strstart(p->filename, "rtsp:", NULL))
91 return AVPROBE_SCORE_MAX;
92 return 0;
93}
94
95static int redir_isspace(int c)
96{
97 return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
98}
99
100static void skip_spaces(const char **pp)
101{
102 const char *p;
103 p = *pp;
104 while (redir_isspace(*p))
105 p++;
106 *pp = p;
107}
108
115329f1 109static void get_word_sep(char *buf, int buf_size, const char *sep,
1617ad97
FB
110 const char **pp)
111{
112 const char *p;
113 char *q;
114
115 p = *pp;
d1ccf0e0
RD
116 if (*p == '/')
117 p++;
1617ad97
FB
118 skip_spaces(&p);
119 q = buf;
120 while (!strchr(sep, *p) && *p != '\0') {
121 if ((q - buf) < buf_size - 1)
122 *q++ = *p;
123 p++;
124 }
125 if (buf_size > 0)
126 *q = '\0';
127 *pp = p;
128}
129
130static void get_word(char *buf, int buf_size, const char **pp)
131{
132 const char *p;
133 char *q;
134
135 p = *pp;
136 skip_spaces(&p);
137 q = buf;
138 while (!redir_isspace(*p) && *p != '\0') {
139 if ((q - buf) < buf_size - 1)
140 *q++ = *p;
141 p++;
142 }
143 if (buf_size > 0)
144 *q = '\0';
145 *pp = p;
146}
147
93ced3e8
FB
148/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
149 params>] */
4934884a 150static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payload_type, const char *p)
93ced3e8
FB
151{
152 char buf[256];
d1ccf0e0
RD
153 int i;
154 AVCodec *c;
7b49ce2e 155 const char *c_name;
93ced3e8 156
d1ccf0e0
RD
157 /* Loop into AVRtpDynamicPayloadTypes[] and AVRtpPayloadTypes[] and
158 see if we can handle this kind of payload */
93ced3e8 159 get_word_sep(buf, sizeof(buf), "/", &p);
d1ccf0e0 160 if (payload_type >= RTP_PT_PRIVATE) {
4934884a
RM
161 RTPDynamicProtocolHandler *handler= RTPFirstDynamicPayloadHandler;
162 while(handler) {
163 if (!strcmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) {
164 codec->codec_id = handler->codec_id;
165 rtsp_st->dynamic_handler= handler;
166 if(handler->open) {
167 rtsp_st->dynamic_protocol_context= handler->open();
168 }
d1ccf0e0
RD
169 break;
170 }
4934884a
RM
171 handler= handler->next;
172 }
93ced3e8 173 } else {
d1ccf0e0
RD
174 /* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */
175 /* search into AVRtpPayloadTypes[] */
176 for (i = 0; AVRtpPayloadTypes[i].pt >= 0; ++i)
177 if (!strcmp(buf, AVRtpPayloadTypes[i].enc_name) && (codec->codec_type == AVRtpPayloadTypes[i].codec_type)){
178 codec->codec_id = AVRtpPayloadTypes[i].codec_id;
179 break;
180 }
181 }
182
183 c = avcodec_find_decoder(codec->codec_id);
184 if (c && c->name)
7b49ce2e 185 c_name = c->name;
d1ccf0e0
RD
186 else
187 c_name = (char *)NULL;
188
189 if (c_name) {
190 get_word_sep(buf, sizeof(buf), "/", &p);
191 i = atoi(buf);
192 switch (codec->codec_type) {
193 case CODEC_TYPE_AUDIO:
194 av_log(codec, AV_LOG_DEBUG, " audio codec set to : %s\n", c_name);
195 codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE;
196 codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS;
197 if (i > 0) {
198 codec->sample_rate = i;
199 get_word_sep(buf, sizeof(buf), "/", &p);
200 i = atoi(buf);
201 if (i > 0)
202 codec->channels = i;
203 }
204 av_log(codec, AV_LOG_DEBUG, " audio samplerate set to : %i\n", codec->sample_rate);
205 av_log(codec, AV_LOG_DEBUG, " audio channels set to : %i\n", codec->channels);
206 break;
207 case CODEC_TYPE_VIDEO:
208 av_log(codec, AV_LOG_DEBUG, " video codec set to : %s\n", c_name);
209 break;
210 default:
211 break;
212 }
213 return 0;
93ced3e8 214 }
d1ccf0e0
RD
215
216 return -1;
93ced3e8
FB
217}
218
219/* return the length and optionnaly the data */
220static int hex_to_data(uint8_t *data, const char *p)
221{
222 int c, len, v;
223
224 len = 0;
225 v = 1;
226 for(;;) {
227 skip_spaces(&p);
228 if (p == '\0')
229 break;
230 c = toupper((unsigned char)*p++);
231 if (c >= '0' && c <= '9')
232 c = c - '0';
233 else if (c >= 'A' && c <= 'F')
234 c = c - 'A' + 10;
235 else
236 break;
237 v = (v << 4) | c;
238 if (v & 0x100) {
239 if (data)
240 data[len] = v;
241 len++;
242 v = 1;
243 }
244 }
245 return len;
246}
247
d1ccf0e0
RD
248static void sdp_parse_fmtp_config(AVCodecContext *codec, char *attr, char *value)
249{
250 switch (codec->codec_id) {
251 case CODEC_ID_MPEG4:
252 case CODEC_ID_MPEG4AAC:
253 if (!strcmp(attr, "config")) {
254 /* decode the hexa encoded parameter */
255 int len = hex_to_data(NULL, value);
256 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
257 if (!codec->extradata)
258 return;
259 codec->extradata_size = len;
260 hex_to_data(codec->extradata, value);
261 }
262 break;
263 default:
264 break;
265 }
266 return;
267}
268
269typedef struct attrname_map
270{
7b49ce2e 271 const char *str;
d1ccf0e0
RD
272 uint16_t type;
273 uint32_t offset;
274} attrname_map_t;
275
276/* All known fmtp parmeters and the corresping RTPAttrTypeEnum */
277#define ATTR_NAME_TYPE_INT 0
278#define ATTR_NAME_TYPE_STR 1
279static attrname_map_t attr_names[]=
280{
281 {"SizeLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, sizelength)},
282 {"IndexLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, indexlength)},
283 {"IndexDeltaLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, indexdeltalength)},
284 {"profile-level-id", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, profile_level_id)},
285 {"StreamType", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, streamtype)},
286 {"mode", ATTR_NAME_TYPE_STR, offsetof(rtp_payload_data_t, mode)},
287 {NULL, -1, -1},
288};
289
290/* parse a SDP line and save stream attributes */
291static void sdp_parse_fmtp(AVStream *st, const char *p)
93ced3e8
FB
292{
293 char attr[256];
294 char value[4096];
d1ccf0e0
RD
295 int i;
296
297 RTSPStream *rtsp_st = st->priv_data;
01f4895c 298 AVCodecContext *codec = st->codec;
d1ccf0e0 299 rtp_payload_data_t *rtp_payload_data = &rtsp_st->rtp_payload_data;
93ced3e8
FB
300
301 /* loop on each attribute */
302 for(;;) {
303 skip_spaces(&p);
304 if (*p == '\0')
305 break;
306 get_word_sep(attr, sizeof(attr), "=", &p);
115329f1 307 if (*p == '=')
93ced3e8
FB
308 p++;
309 get_word_sep(value, sizeof(value), ";", &p);
310 if (*p == ';')
311 p++;
bb270c08 312 /* grab the codec extra_data from the config parameter of the fmtp line */
d1ccf0e0
RD
313 sdp_parse_fmtp_config(codec, attr, value);
314 /* Looking for a known attribute */
315 for (i = 0; attr_names[i].str; ++i) {
316 if (!strcasecmp(attr, attr_names[i].str)) {
317 if (attr_names[i].type == ATTR_NAME_TYPE_INT)
318 *(int *)((char *)rtp_payload_data + attr_names[i].offset) = atoi(value);
319 else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
320 *(char **)((char *)rtp_payload_data + attr_names[i].offset) = av_strdup(value);
bb270c08 321 }
93ced3e8 322 }
93ced3e8
FB
323 }
324}
325
326typedef struct SDPParseState {
327 /* SDP only */
328 struct in_addr default_ip;
329 int default_ttl;
330} SDPParseState;
331
332static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
1617ad97
FB
333 int letter, const char *buf)
334{
8b1ab7bf 335 RTSPState *rt = s->priv_data;
1617ad97
FB
336 char buf1[64], st_type[64];
337 const char *p;
93ced3e8 338 int codec_type, payload_type, i;
1617ad97
FB
339 AVStream *st;
340 RTSPStream *rtsp_st;
93ced3e8
FB
341 struct in_addr sdp_ip;
342 int ttl;
343
1617ad97
FB
344#ifdef DEBUG
345 printf("sdp: %c='%s'\n", letter, buf);
346#endif
347
348 p = buf;
349 switch(letter) {
93ced3e8
FB
350 case 'c':
351 get_word(buf1, sizeof(buf1), &p);
352 if (strcmp(buf1, "IN") != 0)
353 return;
354 get_word(buf1, sizeof(buf1), &p);
355 if (strcmp(buf1, "IP4") != 0)
356 return;
357 get_word_sep(buf1, sizeof(buf1), "/", &p);
358 if (inet_aton(buf1, &sdp_ip) == 0)
359 return;
360 ttl = 16;
361 if (*p == '/') {
362 p++;
363 get_word_sep(buf1, sizeof(buf1), "/", &p);
364 ttl = atoi(buf1);
365 }
366 if (s->nb_streams == 0) {
367 s1->default_ip = sdp_ip;
368 s1->default_ttl = ttl;
369 } else {
370 st = s->streams[s->nb_streams - 1];
371 rtsp_st = st->priv_data;
372 rtsp_st->sdp_ip = sdp_ip;
373 rtsp_st->sdp_ttl = ttl;
374 }
375 break;
1617ad97
FB
376 case 's':
377 pstrcpy(s->title, sizeof(s->title), p);
378 break;
379 case 'i':
380 if (s->nb_streams == 0) {
381 pstrcpy(s->comment, sizeof(s->comment), p);
382 break;
383 }
384 break;
385 case 'm':
386 /* new stream */
387 get_word(st_type, sizeof(st_type), &p);
388 if (!strcmp(st_type, "audio")) {
389 codec_type = CODEC_TYPE_AUDIO;
390 } else if (!strcmp(st_type, "video")) {
391 codec_type = CODEC_TYPE_VIDEO;
392 } else {
393 return;
394 }
1617ad97
FB
395 rtsp_st = av_mallocz(sizeof(RTSPStream));
396 if (!rtsp_st)
397 return;
8b1ab7bf
FB
398 rtsp_st->stream_index = -1;
399 dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st);
93ced3e8
FB
400
401 rtsp_st->sdp_ip = s1->default_ip;
402 rtsp_st->sdp_ttl = s1->default_ttl;
403
93ced3e8
FB
404 get_word(buf1, sizeof(buf1), &p); /* port */
405 rtsp_st->sdp_port = atoi(buf1);
406
407 get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */
115329f1 408
93ced3e8
FB
409 /* XXX: handle list of formats */
410 get_word(buf1, sizeof(buf1), &p); /* format list */
411 rtsp_st->sdp_payload_type = atoi(buf1);
93ced3e8 412
d1ccf0e0 413 if (!strcmp(AVRtpPayloadTypes[rtsp_st->sdp_payload_type].enc_name, "MP2T")) {
8b1ab7bf
FB
414 /* no corresponding stream */
415 } else {
416 st = av_new_stream(s, 0);
417 if (!st)
418 return;
419 st->priv_data = rtsp_st;
420 rtsp_st->stream_index = st->index;
01f4895c 421 st->codec->codec_type = codec_type;
d1ccf0e0 422 if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
8b1ab7bf 423 /* if standard payload type, we can find the codec right now */
01f4895c 424 rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
8b1ab7bf
FB
425 }
426 }
1617ad97
FB
427 /* put a default control url */
428 pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename);
1617ad97
FB
429 break;
430 case 'a':
431 if (strstart(p, "control:", &p) && s->nb_streams > 0) {
432 char proto[32];
433 /* get the control url */
434 st = s->streams[s->nb_streams - 1];
435 rtsp_st = st->priv_data;
115329f1 436
1617ad97 437 /* XXX: may need to add full url resolution */
6ba5cbc6 438 url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p);
1617ad97
FB
439 if (proto[0] == '\0') {
440 /* relative control URL */
441 pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/");
442 pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), p);
443 } else {
444 pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), p);
445 }
93ced3e8
FB
446 } else if (strstart(p, "rtpmap:", &p)) {
447 /* NOTE: rtpmap is only supported AFTER the 'm=' tag */
115329f1 448 get_word(buf1, sizeof(buf1), &p);
93ced3e8
FB
449 payload_type = atoi(buf1);
450 for(i = 0; i < s->nb_streams;i++) {
451 st = s->streams[i];
452 rtsp_st = st->priv_data;
453 if (rtsp_st->sdp_payload_type == payload_type) {
4934884a 454 sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p);
93ced3e8
FB
455 }
456 }
457 } else if (strstart(p, "fmtp:", &p)) {
458 /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */
115329f1 459 get_word(buf1, sizeof(buf1), &p);
93ced3e8
FB
460 payload_type = atoi(buf1);
461 for(i = 0; i < s->nb_streams;i++) {
462 st = s->streams[i];
463 rtsp_st = st->priv_data;
464 if (rtsp_st->sdp_payload_type == payload_type) {
4934884a
RM
465 if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
466 if(!rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf)) {
467 sdp_parse_fmtp(st, p);
468 }
469 } else {
d1ccf0e0 470 sdp_parse_fmtp(st, p);
4934884a 471 }
93ced3e8
FB
472 }
473 }
1617ad97
FB
474 }
475 break;
476 }
477}
478
5c91a675 479static int sdp_parse(AVFormatContext *s, const char *content)
1617ad97
FB
480{
481 const char *p;
482 int letter;
483 char buf[1024], *q;
93ced3e8 484 SDPParseState sdp_parse_state, *s1 = &sdp_parse_state;
115329f1 485
93ced3e8 486 memset(s1, 0, sizeof(SDPParseState));
1617ad97
FB
487 p = content;
488 for(;;) {
489 skip_spaces(&p);
490 letter = *p;
491 if (letter == '\0')
492 break;
493 p++;
494 if (*p != '=')
495 goto next_line;
496 p++;
497 /* get the content */
498 q = buf;
b6892136 499 while (*p != '\n' && *p != '\r' && *p != '\0') {
1617ad97
FB
500 if ((q - buf) < sizeof(buf) - 1)
501 *q++ = *p;
502 p++;
503 }
504 *q = '\0';
93ced3e8 505 sdp_parse_line(s, s1, letter, buf);
1617ad97
FB
506 next_line:
507 while (*p != '\n' && *p != '\0')
508 p++;
509 if (*p == '\n')
510 p++;
511 }
512 return 0;
513}
514
515static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
516{
517 const char *p;
518 int v;
519
520 p = *pp;
521 skip_spaces(&p);
522 v = strtol(p, (char **)&p, 10);
523 if (*p == '-') {
524 p++;
525 *min_ptr = v;
526 v = strtol(p, (char **)&p, 10);
527 *max_ptr = v;
528 } else {
529 *min_ptr = v;
530 *max_ptr = v;
531 }
532 *pp = p;
533}
534
535/* XXX: only one transport specification is parsed */
536static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
537{
538 char transport_protocol[16];
539 char profile[16];
540 char lower_transport[16];
541 char parameter[16];
542 RTSPTransportField *th;
543 char buf[256];
115329f1 544
1617ad97 545 reply->nb_transports = 0;
115329f1 546
1617ad97
FB
547 for(;;) {
548 skip_spaces(&p);
549 if (*p == '\0')
550 break;
551
552 th = &reply->transports[reply->nb_transports];
553
115329f1 554 get_word_sep(transport_protocol, sizeof(transport_protocol),
1617ad97
FB
555 "/", &p);
556 if (*p == '/')
557 p++;
558 get_word_sep(profile, sizeof(profile), "/;,", &p);
559 lower_transport[0] = '\0';
560 if (*p == '/') {
b6892136 561 p++;
115329f1 562 get_word_sep(lower_transport, sizeof(lower_transport),
1617ad97
FB
563 ";,", &p);
564 }
b6892136 565 if (!strcasecmp(lower_transport, "TCP"))
1617ad97
FB
566 th->protocol = RTSP_PROTOCOL_RTP_TCP;
567 else
568 th->protocol = RTSP_PROTOCOL_RTP_UDP;
115329f1 569
1617ad97
FB
570 if (*p == ';')
571 p++;
572 /* get each parameter */
573 while (*p != '\0' && *p != ',') {
574 get_word_sep(parameter, sizeof(parameter), "=;,", &p);
575 if (!strcmp(parameter, "port")) {
576 if (*p == '=') {
577 p++;
578 rtsp_parse_range(&th->port_min, &th->port_max, &p);
579 }
580 } else if (!strcmp(parameter, "client_port")) {
581 if (*p == '=') {
582 p++;
115329f1 583 rtsp_parse_range(&th->client_port_min,
1617ad97
FB
584 &th->client_port_max, &p);
585 }
586 } else if (!strcmp(parameter, "server_port")) {
587 if (*p == '=') {
588 p++;
115329f1 589 rtsp_parse_range(&th->server_port_min,
1617ad97
FB
590 &th->server_port_max, &p);
591 }
592 } else if (!strcmp(parameter, "interleaved")) {
593 if (*p == '=') {
594 p++;
115329f1 595 rtsp_parse_range(&th->interleaved_min,
1617ad97
FB
596 &th->interleaved_max, &p);
597 }
598 } else if (!strcmp(parameter, "multicast")) {
599 if (th->protocol == RTSP_PROTOCOL_RTP_UDP)
600 th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
601 } else if (!strcmp(parameter, "ttl")) {
602 if (*p == '=') {
603 p++;
604 th->ttl = strtol(p, (char **)&p, 10);
605 }
606 } else if (!strcmp(parameter, "destination")) {
607 struct in_addr ipaddr;
608
609 if (*p == '=') {
610 p++;
611 get_word_sep(buf, sizeof(buf), ";,", &p);
115329f1 612 if (inet_aton(buf, &ipaddr))
1617ad97
FB
613 th->destination = ntohl(ipaddr.s_addr);
614 }
615 }
616 while (*p != ';' && *p != '\0' && *p != ',')
617 p++;
618 if (*p == ';')
619 p++;
620 }
621 if (*p == ',')
622 p++;
623
624 reply->nb_transports++;
625 }
626}
627
ff762d6e
FB
628static void rtsp_parse_range_npt(RTSPHeader *reply, const char *p)
629{
630 char buf[256];
631
632 skip_spaces(&p);
633 if (!stristart(p, "npt=", &p))
634 return;
635
636 reply->range_start = AV_NOPTS_VALUE;
637 reply->range_end = AV_NOPTS_VALUE;
115329f1 638
ff762d6e
FB
639 get_word_sep(buf, sizeof(buf), "-", &p);
640 reply->range_start = parse_date(buf, 1);
641 if (*p == '-') {
642 p++;
643 get_word_sep(buf, sizeof(buf), "-", &p);
644 reply->range_end = parse_date(buf, 1);
645 }
646}
647
1617ad97
FB
648void rtsp_parse_line(RTSPHeader *reply, const char *buf)
649{
650 const char *p;
651
652 /* NOTE: we do case independent match for broken servers */
653 p = buf;
654 if (stristart(p, "Session:", &p)) {
655 get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
656 } else if (stristart(p, "Content-Length:", &p)) {
657 reply->content_length = strtol(p, NULL, 10);
658 } else if (stristart(p, "Transport:", &p)) {
659 rtsp_parse_transport(reply, p);
660 } else if (stristart(p, "CSeq:", &p)) {
661 reply->seq = strtol(p, NULL, 10);
ff762d6e
FB
662 } else if (stristart(p, "Range:", &p)) {
663 rtsp_parse_range_npt(reply, p);
1617ad97
FB
664 }
665}
666
2a42b5c3
LS
667static int url_readbuf(URLContext *h, unsigned char *buf, int size)
668{
669 int ret, len;
670
671 len = 0;
672 while (len < size) {
673 ret = url_read(h, buf+len, size-len);
674 if (ret < 1)
675 return ret;
676 len += ret;
677 }
678 return len;
679}
680
b7b8fc34
FB
681/* skip a RTP/TCP interleaved packet */
682static void rtsp_skip_packet(AVFormatContext *s)
683{
684 RTSPState *rt = s->priv_data;
685 int ret, len, len1;
686 uint8_t buf[1024];
687
2a42b5c3 688 ret = url_readbuf(rt->rtsp_hd, buf, 3);
b7b8fc34
FB
689 if (ret != 3)
690 return;
691 len = (buf[1] << 8) | buf[2];
692#ifdef DEBUG
693 printf("skipping RTP packet len=%d\n", len);
694#endif
695 /* skip payload */
696 while (len > 0) {
697 len1 = len;
698 if (len1 > sizeof(buf))
699 len1 = sizeof(buf);
2a42b5c3 700 ret = url_readbuf(rt->rtsp_hd, buf, len1);
b7b8fc34
FB
701 if (ret != len1)
702 return;
703 len -= len1;
704 }
705}
1617ad97 706
115329f1
DB
707static void rtsp_send_cmd(AVFormatContext *s,
708 const char *cmd, RTSPHeader *reply,
1617ad97
FB
709 unsigned char **content_ptr)
710{
711 RTSPState *rt = s->priv_data;
712 char buf[4096], buf1[1024], *q;
713 unsigned char ch;
714 const char *p;
715 int content_length, line_count;
716 unsigned char *content = NULL;
717
718 memset(reply, 0, sizeof(RTSPHeader));
719
720 rt->seq++;
721 pstrcpy(buf, sizeof(buf), cmd);
b6892136 722 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
1617ad97
FB
723 pstrcat(buf, sizeof(buf), buf1);
724 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
b6892136 725 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
1617ad97
FB
726 pstrcat(buf, sizeof(buf), buf1);
727 }
b6892136 728 pstrcat(buf, sizeof(buf), "\r\n");
1617ad97
FB
729#ifdef DEBUG
730 printf("Sending:\n%s--\n", buf);
731#endif
732 url_write(rt->rtsp_hd, buf, strlen(buf));
733
734 /* parse reply (XXX: use buffers) */
735 line_count = 0;
736 rt->last_reply[0] = '\0';
737 for(;;) {
738 q = buf;
739 for(;;) {
2a42b5c3 740 if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1)
1617ad97
FB
741 break;
742 if (ch == '\n')
743 break;
b7b8fc34
FB
744 if (ch == '$') {
745 /* XXX: only parse it if first char on line ? */
746 rtsp_skip_packet(s);
747 } else if (ch != '\r') {
1617ad97
FB
748 if ((q - buf) < sizeof(buf) - 1)
749 *q++ = ch;
750 }
751 }
752 *q = '\0';
753#ifdef DEBUG
754 printf("line='%s'\n", buf);
755#endif
756 /* test if last line */
757 if (buf[0] == '\0')
758 break;
759 p = buf;
760 if (line_count == 0) {
761 /* get reply code */
762 get_word(buf1, sizeof(buf1), &p);
763 get_word(buf1, sizeof(buf1), &p);
764 reply->status_code = atoi(buf1);
765 } else {
766 rtsp_parse_line(reply, p);
767 pstrcat(rt->last_reply, sizeof(rt->last_reply), p);
768 pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n");
769 }
770 line_count++;
771 }
115329f1 772
1617ad97
FB
773 if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
774 pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id);
115329f1 775
1617ad97
FB
776 content_length = reply->content_length;
777 if (content_length > 0) {
778 /* leave some room for a trailing '\0' (useful for simple parsing) */
779 content = av_malloc(content_length + 1);
2a42b5c3 780 (void)url_readbuf(rt->rtsp_hd, content, content_length);
1617ad97
FB
781 content[content_length] = '\0';
782 }
783 if (content_ptr)
784 *content_ptr = content;
785}
786
787/* useful for modules: set RTSP callback function */
788
789void rtsp_set_callback(FFRTSPCallback *rtsp_cb)
790{
791 ff_rtsp_callback = rtsp_cb;
792}
793
794
8b1ab7bf
FB
795/* close and free RTSP streams */
796static void rtsp_close_streams(RTSPState *rt)
797{
798 int i;
799 RTSPStream *rtsp_st;
800
801 for(i=0;i<rt->nb_rtsp_streams;i++) {
802 rtsp_st = rt->rtsp_streams[i];
803 if (rtsp_st) {
804 if (rtsp_st->rtp_ctx)
805 rtp_parse_close(rtsp_st->rtp_ctx);
806 if (rtsp_st->rtp_handle)
807 url_close(rtsp_st->rtp_handle);
4934884a
RM
808 if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
809 rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
8b1ab7bf
FB
810 }
811 av_free(rtsp_st);
812 }
813 av_free(rt->rtsp_streams);
814}
815
1617ad97
FB
816static int rtsp_read_header(AVFormatContext *s,
817 AVFormatParameters *ap)
818{
819 RTSPState *rt = s->priv_data;
820 char host[1024], path[1024], tcpname[1024], cmd[2048];
821 URLContext *rtsp_hd;
d1ccf0e0 822 int port, i, j, ret, err;
1617ad97
FB
823 RTSPHeader reply1, *reply = &reply1;
824 unsigned char *content = NULL;
1617ad97
FB
825 RTSPStream *rtsp_st;
826 int protocol_mask;
8b1ab7bf 827 AVStream *st;
1617ad97 828
1617ad97 829 /* extract hostname and port */
6ba5cbc6 830 url_split(NULL, 0, NULL, 0,
1617ad97
FB
831 host, sizeof(host), &port, path, sizeof(path), s->filename);
832 if (port < 0)
833 port = RTSP_DEFAULT_PORT;
834
835 /* open the tcp connexion */
836 snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
837 if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
838 return AVERROR_IO;
839 rt->rtsp_hd = rtsp_hd;
840 rt->seq = 0;
115329f1 841
1617ad97 842 /* describe the stream */
115329f1 843 snprintf(cmd, sizeof(cmd),
b6892136
FB
844 "DESCRIBE %s RTSP/1.0\r\n"
845 "Accept: application/sdp\r\n",
1617ad97
FB
846 s->filename);
847 rtsp_send_cmd(s, cmd, reply, &content);
848 if (!content) {
849 err = AVERROR_INVALIDDATA;
850 goto fail;
851 }
852 if (reply->status_code != RTSP_STATUS_OK) {
853 err = AVERROR_INVALIDDATA;
854 goto fail;
855 }
115329f1 856
1617ad97
FB
857 /* now we got the SDP description, we parse it */
858 ret = sdp_parse(s, (const char *)content);
859 av_freep(&content);
860 if (ret < 0) {
861 err = AVERROR_INVALIDDATA;
862 goto fail;
863 }
115329f1 864
1617ad97
FB
865 protocol_mask = rtsp_default_protocols;
866
867 /* for each stream, make the setup request */
868 /* XXX: we assume the same server is used for the control of each
869 RTSP stream */
d1ccf0e0
RD
870
871 for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
1617ad97
FB
872 char transport[2048];
873
8b1ab7bf 874 rtsp_st = rt->rtsp_streams[i];
1617ad97
FB
875
876 /* compute available transports */
877 transport[0] = '\0';
878
879 /* RTP/UDP */
880 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) {
85fb7b34 881 char buf[256];
85fb7b34
FB
882
883 /* first try in specified port range */
d1ccf0e0
RD
884 if (RTSP_RTP_PORT_MIN != 0) {
885 while(j <= RTSP_RTP_PORT_MAX) {
85fb7b34 886 snprintf(buf, sizeof(buf), "rtp://?localport=%d", j);
d1ccf0e0
RD
887 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) {
888 j += 2; /* we will use two port by rtp stream (rtp and rtcp) */
85fb7b34 889 goto rtp_opened;
d1ccf0e0 890 }
85fb7b34 891 }
1617ad97 892 }
85fb7b34 893
d1ccf0e0
RD
894/* then try on any port
895** if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) {
896** err = AVERROR_INVALIDDATA;
897** goto fail;
898** }
899*/
85fb7b34
FB
900
901 rtp_opened:
8b1ab7bf 902 port = rtp_get_local_port(rtsp_st->rtp_handle);
1617ad97
FB
903 if (transport[0] != '\0')
904 pstrcat(transport, sizeof(transport), ",");
905 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
906 "RTP/AVP/UDP;unicast;client_port=%d-%d",
907 port, port + 1);
908 }
909
910 /* RTP/TCP */
d1ccf0e0 911 else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {
1617ad97
FB
912 if (transport[0] != '\0')
913 pstrcat(transport, sizeof(transport), ",");
914 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
915 "RTP/AVP/TCP");
916 }
917
d1ccf0e0 918 else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {
1617ad97
FB
919 if (transport[0] != '\0')
920 pstrcat(transport, sizeof(transport), ",");
115329f1 921 snprintf(transport + strlen(transport),
1617ad97
FB
922 sizeof(transport) - strlen(transport) - 1,
923 "RTP/AVP/UDP;multicast");
924 }
115329f1 925 snprintf(cmd, sizeof(cmd),
b6892136
FB
926 "SETUP %s RTSP/1.0\r\n"
927 "Transport: %s\r\n",
1617ad97
FB
928 rtsp_st->control_url, transport);
929 rtsp_send_cmd(s, cmd, reply, NULL);
930 if (reply->status_code != RTSP_STATUS_OK ||
931 reply->nb_transports != 1) {
932 err = AVERROR_INVALIDDATA;
933 goto fail;
934 }
935
936 /* XXX: same protocol for all streams is required */
937 if (i > 0) {
938 if (reply->transports[0].protocol != rt->protocol) {
939 err = AVERROR_INVALIDDATA;
940 goto fail;
941 }
942 } else {
943 rt->protocol = reply->transports[0].protocol;
944 }
945
946 /* close RTP connection if not choosen */
947 if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP &&
948 (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) {
8b1ab7bf
FB
949 url_close(rtsp_st->rtp_handle);
950 rtsp_st->rtp_handle = NULL;
1617ad97
FB
951 }
952
953 switch(reply->transports[0].protocol) {
954 case RTSP_PROTOCOL_RTP_TCP:
1617ad97
FB
955 rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
956 rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
957 break;
115329f1 958
1617ad97
FB
959 case RTSP_PROTOCOL_RTP_UDP:
960 {
961 char url[1024];
115329f1 962
1617ad97 963 /* XXX: also use address if specified */
115329f1 964 snprintf(url, sizeof(url), "rtp://%s:%d",
1617ad97 965 host, reply->transports[0].server_port_min);
8b1ab7bf 966 if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
1617ad97
FB
967 err = AVERROR_INVALIDDATA;
968 goto fail;
969 }
970 }
971 break;
972 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
973 {
974 char url[1024];
975 int ttl;
976
1617ad97
FB
977 ttl = reply->transports[0].ttl;
978 if (!ttl)
979 ttl = 16;
115329f1
DB
980 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
981 host,
1617ad97
FB
982 reply->transports[0].server_port_min,
983 ttl);
8b1ab7bf 984 if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) {
1617ad97
FB
985 err = AVERROR_INVALIDDATA;
986 goto fail;
987 }
988 }
989 break;
990 }
8b1ab7bf
FB
991 /* open the RTP context */
992 st = NULL;
993 if (rtsp_st->stream_index >= 0)
994 st = s->streams[rtsp_st->stream_index];
995 if (!st)
996 s->ctx_flags |= AVFMTCTX_NOHEADER;
d1ccf0e0
RD
997 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
998
8b1ab7bf
FB
999 if (!rtsp_st->rtp_ctx) {
1000 err = AVERROR_NOMEM;
1001 goto fail;
4934884a
RM
1002 } else {
1003 if(rtsp_st->dynamic_handler) {
1004 rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
1005 rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
1006 }
8b1ab7bf 1007 }
1617ad97
FB
1008 }
1009
1010 /* use callback if available to extend setup */
1011 if (ff_rtsp_callback) {
115329f1 1012 if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id,
1617ad97
FB
1013 NULL, 0, rt->last_reply) < 0) {
1014 err = AVERROR_INVALIDDATA;
1015 goto fail;
1016 }
1017 }
115329f1 1018
1617ad97 1019
ff762d6e
FB
1020 rt->state = RTSP_STATE_IDLE;
1021 rt->seek_timestamp = 0; /* default is to start stream at position
1022 zero */
c04c3282 1023 if (ap->initial_pause) {
ff762d6e
FB
1024 /* do not start immediately */
1025 } else {
1026 if (rtsp_read_play(s) < 0) {
1027 err = AVERROR_INVALIDDATA;
1617ad97
FB
1028 goto fail;
1029 }
1030 }
1617ad97
FB
1031 return 0;
1032 fail:
8b1ab7bf 1033 rtsp_close_streams(rt);
1617ad97
FB
1034 av_freep(&content);
1035 url_close(rt->rtsp_hd);
1036 return err;
1037}
1038
8b1ab7bf
FB
1039static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
1040 uint8_t *buf, int buf_size)
1617ad97
FB
1041{
1042 RTSPState *rt = s->priv_data;
b6892136 1043 int id, len, i, ret;
1617ad97 1044 RTSPStream *rtsp_st;
1617ad97 1045
b6892136
FB
1046#ifdef DEBUG_RTP_TCP
1047 printf("tcp_read_packet:\n");
1048#endif
1617ad97
FB
1049 redo:
1050 for(;;) {
2a42b5c3 1051 ret = url_readbuf(rt->rtsp_hd, buf, 1);
b6892136
FB
1052#ifdef DEBUG_RTP_TCP
1053 printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
1054#endif
1055 if (ret != 1)
8b1ab7bf 1056 return -1;
b6892136 1057 if (buf[0] == '$')
1617ad97
FB
1058 break;
1059 }
2a42b5c3 1060 ret = url_readbuf(rt->rtsp_hd, buf, 3);
b6892136 1061 if (ret != 3)
8b1ab7bf 1062 return -1;
b6892136
FB
1063 id = buf[0];
1064 len = (buf[1] << 8) | buf[2];
1065#ifdef DEBUG_RTP_TCP
1066 printf("id=%d len=%d\n", id, len);
1067#endif
8b1ab7bf 1068 if (len > buf_size || len < 12)
1617ad97
FB
1069 goto redo;
1070 /* get the data */
2a42b5c3 1071 ret = url_readbuf(rt->rtsp_hd, buf, len);
b6892136 1072 if (ret != len)
8b1ab7bf 1073 return -1;
115329f1 1074
1617ad97 1075 /* find the matching stream */
8b1ab7bf
FB
1076 for(i = 0; i < rt->nb_rtsp_streams; i++) {
1077 rtsp_st = rt->rtsp_streams[i];
115329f1
DB
1078 if (id >= rtsp_st->interleaved_min &&
1079 id <= rtsp_st->interleaved_max)
1617ad97
FB
1080 goto found;
1081 }
1082 goto redo;
1083 found:
8b1ab7bf
FB
1084 *prtsp_st = rtsp_st;
1085 return len;
1617ad97
FB
1086}
1087
115329f1 1088static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
8b1ab7bf 1089 uint8_t *buf, int buf_size)
1617ad97 1090{
8b1ab7bf 1091 RTSPState *rt = s->priv_data;
1617ad97
FB
1092 RTSPStream *rtsp_st;
1093 fd_set rfds;
1094 int fd1, fd2, fd_max, n, i, ret;
1617ad97
FB
1095 struct timeval tv;
1096
1097 for(;;) {
b7b8fc34 1098 if (url_interrupt_cb())
8b1ab7bf 1099 return -1;
1617ad97
FB
1100 FD_ZERO(&rfds);
1101 fd_max = -1;
8b1ab7bf
FB
1102 for(i = 0; i < rt->nb_rtsp_streams; i++) {
1103 rtsp_st = rt->rtsp_streams[i];
1617ad97 1104 /* currently, we cannot probe RTCP handle because of blocking restrictions */
8b1ab7bf 1105 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
1617ad97
FB
1106 if (fd1 > fd_max)
1107 fd_max = fd1;
1108 FD_SET(fd1, &rfds);
1109 }
1617ad97 1110 tv.tv_sec = 0;
b7b8fc34 1111 tv.tv_usec = 100 * 1000;
1617ad97
FB
1112 n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
1113 if (n > 0) {
8b1ab7bf
FB
1114 for(i = 0; i < rt->nb_rtsp_streams; i++) {
1115 rtsp_st = rt->rtsp_streams[i];
1116 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
1617ad97 1117 if (FD_ISSET(fd1, &rfds)) {
8b1ab7bf
FB
1118 ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
1119 if (ret > 0) {
1120 *prtsp_st = rtsp_st;
1617ad97
FB
1121 return ret;
1122 }
1123 }
1124 }
1125 }
1126 }
1127}
1128
1129static int rtsp_read_packet(AVFormatContext *s,
1130 AVPacket *pkt)
1131{
1132 RTSPState *rt = s->priv_data;
8b1ab7bf
FB
1133 RTSPStream *rtsp_st;
1134 int ret, len;
1135 uint8_t buf[RTP_MAX_PACKET_LENGTH];
1136
1137 /* get next frames from the same RTP packet */
1138 if (rt->cur_rtp) {
1139 ret = rtp_parse_packet(rt->cur_rtp, pkt, NULL, 0);
1140 if (ret == 0) {
1141 rt->cur_rtp = NULL;
1142 return 0;
1143 } else if (ret == 1) {
1144 return 0;
1145 } else {
1146 rt->cur_rtp = NULL;
1147 }
1148 }
1617ad97 1149
8b1ab7bf
FB
1150 /* read next RTP packet */
1151 redo:
1617ad97
FB
1152 switch(rt->protocol) {
1153 default:
1154 case RTSP_PROTOCOL_RTP_TCP:
8b1ab7bf 1155 len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
1617ad97
FB
1156 break;
1157 case RTSP_PROTOCOL_RTP_UDP:
8b1ab7bf
FB
1158 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
1159 len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
1617ad97
FB
1160 break;
1161 }
8b1ab7bf
FB
1162 if (len < 0)
1163 return AVERROR_IO;
1164 ret = rtp_parse_packet(rtsp_st->rtp_ctx, pkt, buf, len);
1165 if (ret < 0)
1166 goto redo;
1167 if (ret == 1) {
1168 /* more packets may follow, so we save the RTP context */
1169 rt->cur_rtp = rtsp_st->rtp_ctx;
1170 }
1171 return 0;
1617ad97
FB
1172}
1173
ff762d6e 1174static int rtsp_read_play(AVFormatContext *s)
b7b8fc34 1175{
ff762d6e 1176 RTSPState *rt = s->priv_data;
b7b8fc34
FB
1177 RTSPHeader reply1, *reply = &reply1;
1178 char cmd[1024];
1179
bc874dae 1180 av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
ff762d6e
FB
1181
1182 if (rt->state == RTSP_STATE_PAUSED) {
115329f1 1183 snprintf(cmd, sizeof(cmd),
ff762d6e
FB
1184 "PLAY %s RTSP/1.0\r\n",
1185 s->filename);
1186 } else {
115329f1 1187 snprintf(cmd, sizeof(cmd),
ff762d6e
FB
1188 "PLAY %s RTSP/1.0\r\n"
1189 "Range: npt=%0.3f-\r\n",
1190 s->filename,
1191 (double)rt->seek_timestamp / AV_TIME_BASE);
1192 }
b7b8fc34
FB
1193 rtsp_send_cmd(s, cmd, reply, NULL);
1194 if (reply->status_code != RTSP_STATUS_OK) {
1195 return -1;
1196 } else {
ff762d6e 1197 rt->state = RTSP_STATE_PLAYING;
b7b8fc34
FB
1198 return 0;
1199 }
1200}
1201
ff762d6e
FB
1202/* pause the stream */
1203static int rtsp_read_pause(AVFormatContext *s)
b7b8fc34 1204{
ff762d6e 1205 RTSPState *rt = s->priv_data;
b7b8fc34
FB
1206 RTSPHeader reply1, *reply = &reply1;
1207 char cmd[1024];
1208
b7b8fc34 1209 rt = s->priv_data;
115329f1 1210
ff762d6e
FB
1211 if (rt->state != RTSP_STATE_PLAYING)
1212 return 0;
1213
115329f1 1214 snprintf(cmd, sizeof(cmd),
ff762d6e 1215 "PAUSE %s RTSP/1.0\r\n",
b7b8fc34
FB
1216 s->filename);
1217 rtsp_send_cmd(s, cmd, reply, NULL);
1218 if (reply->status_code != RTSP_STATUS_OK) {
1219 return -1;
1220 } else {
ff762d6e 1221 rt->state = RTSP_STATE_PAUSED;
b7b8fc34
FB
1222 return 0;
1223 }
1224}
1225
115329f1 1226static int rtsp_read_seek(AVFormatContext *s, int stream_index,
7b3c1382 1227 int64_t timestamp, int flags)
ff762d6e
FB
1228{
1229 RTSPState *rt = s->priv_data;
115329f1 1230
ff762d6e
FB
1231 rt->seek_timestamp = timestamp;
1232 switch(rt->state) {
1233 default:
1234 case RTSP_STATE_IDLE:
1235 break;
1236 case RTSP_STATE_PLAYING:
1237 if (rtsp_read_play(s) != 0)
1238 return -1;
1239 break;
1240 case RTSP_STATE_PAUSED:
1241 rt->state = RTSP_STATE_IDLE;
1242 break;
1243 }
1244 return 0;
1245}
1246
1617ad97
FB
1247static int rtsp_read_close(AVFormatContext *s)
1248{
1249 RTSPState *rt = s->priv_data;
1617ad97 1250 RTSPHeader reply1, *reply = &reply1;
1617ad97
FB
1251 char cmd[1024];
1252
b6892136 1253#if 0
1617ad97
FB
1254 /* NOTE: it is valid to flush the buffer here */
1255 if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
1256 url_fclose(&rt->rtsp_gb);
1257 }
b6892136 1258#endif
115329f1 1259 snprintf(cmd, sizeof(cmd),
b6892136 1260 "TEARDOWN %s RTSP/1.0\r\n",
1617ad97
FB
1261 s->filename);
1262 rtsp_send_cmd(s, cmd, reply, NULL);
1263
1264 if (ff_rtsp_callback) {
115329f1 1265 ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id,
1617ad97
FB
1266 NULL, 0, NULL);
1267 }
1268
8b1ab7bf 1269 rtsp_close_streams(rt);
1617ad97
FB
1270 url_close(rt->rtsp_hd);
1271 return 0;
1272}
1273
d2a067d1 1274AVInputFormat rtsp_demuxer = {
1617ad97
FB
1275 "rtsp",
1276 "RTSP input format",
1277 sizeof(RTSPState),
1278 rtsp_probe,
1279 rtsp_read_header,
1280 rtsp_read_packet,
1281 rtsp_read_close,
ff762d6e 1282 rtsp_read_seek,
bb76a117 1283 .flags = AVFMT_NOFILE,
ff762d6e
FB
1284 .read_play = rtsp_read_play,
1285 .read_pause = rtsp_read_pause,
1617ad97
FB
1286};
1287
cb1fdc61 1288static int sdp_probe(AVProbeData *p1)
93ced3e8 1289{
0e1ceacd 1290 const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
cb1fdc61
FB
1291
1292 /* we look for a line beginning "c=IN IP4" */
0e1ceacd
MN
1293 while (p < p_end && *p != '\0') {
1294 if (p + sizeof("c=IN IP4") - 1 < p_end && strstart(p, "c=IN IP4", NULL))
cb1fdc61 1295 return AVPROBE_SCORE_MAX / 2;
0e1ceacd
MN
1296
1297 while(p < p_end - 1 && *p != '\n') p++;
1298 if (++p >= p_end)
cb1fdc61 1299 break;
cb1fdc61
FB
1300 if (*p == '\r')
1301 p++;
1302 }
93ced3e8
FB
1303 return 0;
1304}
1305
1306#define SDP_MAX_SIZE 8192
1307
1308static int sdp_read_header(AVFormatContext *s,
1309 AVFormatParameters *ap)
1310{
8b1ab7bf 1311 RTSPState *rt = s->priv_data;
93ced3e8
FB
1312 RTSPStream *rtsp_st;
1313 int size, i, err;
1314 char *content;
1315 char url[1024];
8b1ab7bf 1316 AVStream *st;
93ced3e8
FB
1317
1318 /* read the whole sdp file */
1319 /* XXX: better loading */
1320 content = av_malloc(SDP_MAX_SIZE);
1321 size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1);
1322 if (size <= 0) {
1323 av_free(content);
1324 return AVERROR_INVALIDDATA;
1325 }
1326 content[size] ='\0';
1327
1328 sdp_parse(s, content);
1329 av_free(content);
1330
1331 /* open each RTP stream */
8b1ab7bf
FB
1332 for(i=0;i<rt->nb_rtsp_streams;i++) {
1333 rtsp_st = rt->rtsp_streams[i];
115329f1
DB
1334
1335 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
1336 inet_ntoa(rtsp_st->sdp_ip),
93ced3e8
FB
1337 rtsp_st->sdp_port,
1338 rtsp_st->sdp_ttl);
8b1ab7bf 1339 if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) {
93ced3e8
FB
1340 err = AVERROR_INVALIDDATA;
1341 goto fail;
1342 }
8b1ab7bf
FB
1343 /* open the RTP context */
1344 st = NULL;
1345 if (rtsp_st->stream_index >= 0)
1346 st = s->streams[rtsp_st->stream_index];
1347 if (!st)
1348 s->ctx_flags |= AVFMTCTX_NOHEADER;
d1ccf0e0 1349 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
8b1ab7bf
FB
1350 if (!rtsp_st->rtp_ctx) {
1351 err = AVERROR_NOMEM;
1352 goto fail;
4934884a
RM
1353 } else {
1354 if(rtsp_st->dynamic_handler) {
1355 rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
1356 rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
1357 }
8b1ab7bf 1358 }
93ced3e8
FB
1359 }
1360 return 0;
1361 fail:
8b1ab7bf 1362 rtsp_close_streams(rt);
93ced3e8
FB
1363 return err;
1364}
1365
1366static int sdp_read_packet(AVFormatContext *s,
1367 AVPacket *pkt)
1368{
8b1ab7bf 1369 return rtsp_read_packet(s, pkt);
93ced3e8
FB
1370}
1371
1372static int sdp_read_close(AVFormatContext *s)
1373{
8b1ab7bf
FB
1374 RTSPState *rt = s->priv_data;
1375 rtsp_close_streams(rt);
93ced3e8
FB
1376 return 0;
1377}
1378
ff70e601
MR
1379#ifdef CONFIG_SDP_DEMUXER
1380AVInputFormat sdp_demuxer = {
93ced3e8
FB
1381 "sdp",
1382 "SDP",
1383 sizeof(RTSPState),
1384 sdp_probe,
1385 sdp_read_header,
1386 sdp_read_packet,
1387 sdp_read_close,
1388};
ff70e601 1389#endif
93ced3e8 1390
1617ad97
FB
1391/* dummy redirector format (used directly in av_open_input_file now) */
1392static int redir_probe(AVProbeData *pd)
1393{
1394 const char *p;
1395 p = pd->buf;
1396 while (redir_isspace(*p))
1397 p++;
1398 if (strstart(p, "http://", NULL) ||
1399 strstart(p, "rtsp://", NULL))
1400 return AVPROBE_SCORE_MAX;
1401 return 0;
1402}
1403
1404/* called from utils.c */
1405int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f)
1406{
1407 char buf[4096], *q;
1408 int c;
1409 AVFormatContext *ic = NULL;
1410
1411 /* parse each URL and try to open it */
1412 c = url_fgetc(f);
1413 while (c != URL_EOF) {
1414 /* skip spaces */
1415 for(;;) {
1416 if (!redir_isspace(c))
1417 break;
1418 c = url_fgetc(f);
1419 }
1420 if (c == URL_EOF)
1421 break;
1422 /* record url */
1423 q = buf;
1424 for(;;) {
1425 if (c == URL_EOF || redir_isspace(c))
1426 break;
1427 if ((q - buf) < sizeof(buf) - 1)
1428 *q++ = c;
1429 c = url_fgetc(f);
1430 }
1431 *q = '\0';
1432 //printf("URL='%s'\n", buf);
1433 /* try to open the media file */
1434 if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
1435 break;
1436 }
1437 *ic_ptr = ic;
1438 if (!ic)
1439 return AVERROR_IO;
1440 else
1441 return 0;
1442}
1443
d2a067d1 1444AVInputFormat redir_demuxer = {
1617ad97
FB
1445 "redir",
1446 "Redirector format",
1447 0,
1448 redir_probe,
1449 NULL,
1450 NULL,
1451 NULL,
1452};