update copyright year, it looks odd otherwise :)
[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 {
ed787542 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);
dbf30963 887 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) {
d1ccf0e0 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);
dbf30963 984 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 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;
dbf30963 997 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
d1ccf0e0 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));
dbf30963
T
1160 if (rtsp_st->rtp_ctx)
1161 rtp_check_and_send_back_rr(rtsp_st->rtp_ctx, len);
1617ad97
FB
1162 break;
1163 }
8b1ab7bf
FB
1164 if (len < 0)
1165 return AVERROR_IO;
1166 ret = rtp_parse_packet(rtsp_st->rtp_ctx, pkt, buf, len);
1167 if (ret < 0)
1168 goto redo;
1169 if (ret == 1) {
1170 /* more packets may follow, so we save the RTP context */
1171 rt->cur_rtp = rtsp_st->rtp_ctx;
1172 }
1173 return 0;
1617ad97
FB
1174}
1175
ff762d6e 1176static int rtsp_read_play(AVFormatContext *s)
b7b8fc34 1177{
ff762d6e 1178 RTSPState *rt = s->priv_data;
b7b8fc34
FB
1179 RTSPHeader reply1, *reply = &reply1;
1180 char cmd[1024];
1181
bc874dae 1182 av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
ff762d6e
FB
1183
1184 if (rt->state == RTSP_STATE_PAUSED) {
115329f1 1185 snprintf(cmd, sizeof(cmd),
ff762d6e
FB
1186 "PLAY %s RTSP/1.0\r\n",
1187 s->filename);
1188 } else {
115329f1 1189 snprintf(cmd, sizeof(cmd),
ff762d6e
FB
1190 "PLAY %s RTSP/1.0\r\n"
1191 "Range: npt=%0.3f-\r\n",
1192 s->filename,
1193 (double)rt->seek_timestamp / AV_TIME_BASE);
1194 }
b7b8fc34
FB
1195 rtsp_send_cmd(s, cmd, reply, NULL);
1196 if (reply->status_code != RTSP_STATUS_OK) {
1197 return -1;
1198 } else {
ff762d6e 1199 rt->state = RTSP_STATE_PLAYING;
b7b8fc34
FB
1200 return 0;
1201 }
1202}
1203
ff762d6e
FB
1204/* pause the stream */
1205static int rtsp_read_pause(AVFormatContext *s)
b7b8fc34 1206{
ff762d6e 1207 RTSPState *rt = s->priv_data;
b7b8fc34
FB
1208 RTSPHeader reply1, *reply = &reply1;
1209 char cmd[1024];
1210
b7b8fc34 1211 rt = s->priv_data;
115329f1 1212
ff762d6e
FB
1213 if (rt->state != RTSP_STATE_PLAYING)
1214 return 0;
1215
115329f1 1216 snprintf(cmd, sizeof(cmd),
ff762d6e 1217 "PAUSE %s RTSP/1.0\r\n",
b7b8fc34
FB
1218 s->filename);
1219 rtsp_send_cmd(s, cmd, reply, NULL);
1220 if (reply->status_code != RTSP_STATUS_OK) {
1221 return -1;
1222 } else {
ff762d6e 1223 rt->state = RTSP_STATE_PAUSED;
b7b8fc34
FB
1224 return 0;
1225 }
1226}
1227
115329f1 1228static int rtsp_read_seek(AVFormatContext *s, int stream_index,
7b3c1382 1229 int64_t timestamp, int flags)
ff762d6e
FB
1230{
1231 RTSPState *rt = s->priv_data;
115329f1 1232
ff762d6e
FB
1233 rt->seek_timestamp = timestamp;
1234 switch(rt->state) {
1235 default:
1236 case RTSP_STATE_IDLE:
1237 break;
1238 case RTSP_STATE_PLAYING:
1239 if (rtsp_read_play(s) != 0)
1240 return -1;
1241 break;
1242 case RTSP_STATE_PAUSED:
1243 rt->state = RTSP_STATE_IDLE;
1244 break;
1245 }
1246 return 0;
1247}
1248
1617ad97
FB
1249static int rtsp_read_close(AVFormatContext *s)
1250{
1251 RTSPState *rt = s->priv_data;
1617ad97 1252 RTSPHeader reply1, *reply = &reply1;
1617ad97
FB
1253 char cmd[1024];
1254
b6892136 1255#if 0
1617ad97
FB
1256 /* NOTE: it is valid to flush the buffer here */
1257 if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
1258 url_fclose(&rt->rtsp_gb);
1259 }
b6892136 1260#endif
115329f1 1261 snprintf(cmd, sizeof(cmd),
b6892136 1262 "TEARDOWN %s RTSP/1.0\r\n",
1617ad97
FB
1263 s->filename);
1264 rtsp_send_cmd(s, cmd, reply, NULL);
1265
1266 if (ff_rtsp_callback) {
115329f1 1267 ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id,
1617ad97
FB
1268 NULL, 0, NULL);
1269 }
1270
8b1ab7bf 1271 rtsp_close_streams(rt);
1617ad97
FB
1272 url_close(rt->rtsp_hd);
1273 return 0;
1274}
1275
d2a067d1 1276AVInputFormat rtsp_demuxer = {
1617ad97
FB
1277 "rtsp",
1278 "RTSP input format",
1279 sizeof(RTSPState),
1280 rtsp_probe,
1281 rtsp_read_header,
1282 rtsp_read_packet,
1283 rtsp_read_close,
ff762d6e 1284 rtsp_read_seek,
bb76a117 1285 .flags = AVFMT_NOFILE,
ff762d6e
FB
1286 .read_play = rtsp_read_play,
1287 .read_pause = rtsp_read_pause,
1617ad97
FB
1288};
1289
cb1fdc61 1290static int sdp_probe(AVProbeData *p1)
93ced3e8 1291{
0e1ceacd 1292 const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
cb1fdc61
FB
1293
1294 /* we look for a line beginning "c=IN IP4" */
0e1ceacd
MN
1295 while (p < p_end && *p != '\0') {
1296 if (p + sizeof("c=IN IP4") - 1 < p_end && strstart(p, "c=IN IP4", NULL))
cb1fdc61 1297 return AVPROBE_SCORE_MAX / 2;
0e1ceacd
MN
1298
1299 while(p < p_end - 1 && *p != '\n') p++;
1300 if (++p >= p_end)
cb1fdc61 1301 break;
cb1fdc61
FB
1302 if (*p == '\r')
1303 p++;
1304 }
93ced3e8
FB
1305 return 0;
1306}
1307
1308#define SDP_MAX_SIZE 8192
1309
1310static int sdp_read_header(AVFormatContext *s,
1311 AVFormatParameters *ap)
1312{
8b1ab7bf 1313 RTSPState *rt = s->priv_data;
93ced3e8
FB
1314 RTSPStream *rtsp_st;
1315 int size, i, err;
1316 char *content;
1317 char url[1024];
8b1ab7bf 1318 AVStream *st;
93ced3e8
FB
1319
1320 /* read the whole sdp file */
1321 /* XXX: better loading */
1322 content = av_malloc(SDP_MAX_SIZE);
1323 size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1);
1324 if (size <= 0) {
1325 av_free(content);
1326 return AVERROR_INVALIDDATA;
1327 }
1328 content[size] ='\0';
1329
1330 sdp_parse(s, content);
1331 av_free(content);
1332
1333 /* open each RTP stream */
8b1ab7bf
FB
1334 for(i=0;i<rt->nb_rtsp_streams;i++) {
1335 rtsp_st = rt->rtsp_streams[i];
115329f1
DB
1336
1337 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
1338 inet_ntoa(rtsp_st->sdp_ip),
93ced3e8
FB
1339 rtsp_st->sdp_port,
1340 rtsp_st->sdp_ttl);
dbf30963 1341 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
93ced3e8
FB
1342 err = AVERROR_INVALIDDATA;
1343 goto fail;
1344 }
8b1ab7bf
FB
1345 /* open the RTP context */
1346 st = NULL;
1347 if (rtsp_st->stream_index >= 0)
1348 st = s->streams[rtsp_st->stream_index];
1349 if (!st)
1350 s->ctx_flags |= AVFMTCTX_NOHEADER;
dbf30963 1351 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
8b1ab7bf
FB
1352 if (!rtsp_st->rtp_ctx) {
1353 err = AVERROR_NOMEM;
1354 goto fail;
4934884a
RM
1355 } else {
1356 if(rtsp_st->dynamic_handler) {
1357 rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
1358 rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
1359 }
8b1ab7bf 1360 }
93ced3e8
FB
1361 }
1362 return 0;
1363 fail:
8b1ab7bf 1364 rtsp_close_streams(rt);
93ced3e8
FB
1365 return err;
1366}
1367
1368static int sdp_read_packet(AVFormatContext *s,
1369 AVPacket *pkt)
1370{
8b1ab7bf 1371 return rtsp_read_packet(s, pkt);
93ced3e8
FB
1372}
1373
1374static int sdp_read_close(AVFormatContext *s)
1375{
8b1ab7bf
FB
1376 RTSPState *rt = s->priv_data;
1377 rtsp_close_streams(rt);
93ced3e8
FB
1378 return 0;
1379}
1380
ff70e601
MR
1381#ifdef CONFIG_SDP_DEMUXER
1382AVInputFormat sdp_demuxer = {
93ced3e8
FB
1383 "sdp",
1384 "SDP",
1385 sizeof(RTSPState),
1386 sdp_probe,
1387 sdp_read_header,
1388 sdp_read_packet,
1389 sdp_read_close,
1390};
ff70e601 1391#endif
93ced3e8 1392
1617ad97
FB
1393/* dummy redirector format (used directly in av_open_input_file now) */
1394static int redir_probe(AVProbeData *pd)
1395{
1396 const char *p;
1397 p = pd->buf;
1398 while (redir_isspace(*p))
1399 p++;
1400 if (strstart(p, "http://", NULL) ||
1401 strstart(p, "rtsp://", NULL))
1402 return AVPROBE_SCORE_MAX;
1403 return 0;
1404}
1405
1406/* called from utils.c */
1407int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f)
1408{
1409 char buf[4096], *q;
1410 int c;
1411 AVFormatContext *ic = NULL;
1412
1413 /* parse each URL and try to open it */
1414 c = url_fgetc(f);
1415 while (c != URL_EOF) {
1416 /* skip spaces */
1417 for(;;) {
1418 if (!redir_isspace(c))
1419 break;
1420 c = url_fgetc(f);
1421 }
1422 if (c == URL_EOF)
1423 break;
1424 /* record url */
1425 q = buf;
1426 for(;;) {
1427 if (c == URL_EOF || redir_isspace(c))
1428 break;
1429 if ((q - buf) < sizeof(buf) - 1)
1430 *q++ = c;
1431 c = url_fgetc(f);
1432 }
1433 *q = '\0';
1434 //printf("URL='%s'\n", buf);
1435 /* try to open the media file */
1436 if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
1437 break;
1438 }
1439 *ic_ptr = ic;
1440 if (!ic)
1441 return AVERROR_IO;
1442 else
1443 return 0;
1444}
1445
d2a067d1 1446AVInputFormat redir_demuxer = {
1617ad97
FB
1447 "redir",
1448 "Redirector format",
1449 0,
1450 redir_probe,
1451 NULL,
1452 NULL,
1453 NULL,
1454};