| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |  * RTSP/SDP client | 
					
						
							| 
									
										
										
										
											2009-01-19 15:46:40 +00:00
										 |  |  |  * Copyright (c) 2002 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * This file is part of FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is free software; you can redistribute it and/or | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * FFmpeg is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * License along with FFmpeg; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2006-01-12 22:43:26 +00:00
										 |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-05-09 11:56:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 21:47:11 +00:00
										 |  |  | #include "libavutil/base64.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-09 11:56:36 +00:00
										 |  |  | #include "libavutil/avstring.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-11 22:19:48 +00:00
										 |  |  | #include "libavutil/intreadwrite.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  | #include "libavutil/random_seed.h"
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | #include "avformat.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-22 08:40:33 +00:00
										 |  |  | #include <sys/time.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-13 23:44:16 +00:00
										 |  |  | #if HAVE_SYS_SELECT_H
 | 
					
						
							| 
									
										
										
										
											2008-09-24 22:08:50 +00:00
										 |  |  | #include <sys/select.h>
 | 
					
						
							| 
									
										
										
										
											2008-09-26 02:12:37 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-08-13 17:22:53 +00:00
										 |  |  | #include <strings.h>
 | 
					
						
							| 
									
										
										
										
											2010-03-14 23:59:48 +00:00
										 |  |  | #include "internal.h"
 | 
					
						
							| 
									
										
										
										
											2007-02-04 17:05:44 +00:00
										 |  |  | #include "network.h"
 | 
					
						
							| 
									
										
										
										
											2010-03-10 07:44:51 +00:00
										 |  |  | #include "os_support.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  | #include "http.h"
 | 
					
						
							| 
									
										
										
										
											2007-10-29 09:15:35 +00:00
										 |  |  | #include "rtsp.h"
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-06 10:35:52 +00:00
										 |  |  | #include "rtpdec.h"
 | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  | #include "rdt.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-30 12:04:27 +00:00
										 |  |  | #include "rtpdec_formats.h"
 | 
					
						
							| 
									
										
										
										
											2006-10-26 18:36:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | //#define DEBUG
 | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | //#define DEBUG_RTP_TCP
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-02 19:40:43 +00:00
										 |  |  | #if LIBAVFORMAT_VERSION_INT < (53 << 16)
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  | int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP); | 
					
						
							| 
									
										
										
										
											2008-01-02 19:40:43 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-24 17:40:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-29 19:17:49 +00:00
										 |  |  | /* Timeout values for socket select, in ms,
 | 
					
						
							| 
									
										
										
										
											2010-03-29 17:36:08 +00:00
										 |  |  |  * and read_packet(), in seconds  */ | 
					
						
							|  |  |  | #define SELECT_TIMEOUT_MS 100
 | 
					
						
							|  |  |  | #define READ_PACKET_TIMEOUT_S 10
 | 
					
						
							|  |  |  | #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / SELECT_TIMEOUT_MS
 | 
					
						
							| 
									
										
										
										
											2010-08-07 11:16:07 +00:00
										 |  |  | #define SDP_MAX_SIZE 16384
 | 
					
						
							| 
									
										
										
										
											2010-03-29 17:36:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 20:54:47 +00:00
										 |  |  | static void get_word_until_chars(char *buf, int buf_size, | 
					
						
							|  |  |  |                                  const char *sep, const char **pp) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     char *q; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     p = *pp; | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |     p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     q = buf; | 
					
						
							|  |  |  |     while (!strchr(sep, *p) && *p != '\0') { | 
					
						
							|  |  |  |         if ((q - buf) < buf_size - 1) | 
					
						
							|  |  |  |             *q++ = *p; | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (buf_size > 0) | 
					
						
							|  |  |  |         *q = '\0'; | 
					
						
							|  |  |  |     *pp = p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 20:54:47 +00:00
										 |  |  | static void get_word_sep(char *buf, int buf_size, const char *sep, | 
					
						
							|  |  |  |                          const char **pp) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-03-21 20:54:47 +00:00
										 |  |  |     if (**pp == '/') (*pp)++; | 
					
						
							|  |  |  |     get_word_until_chars(buf, buf_size, sep, pp); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 20:54:47 +00:00
										 |  |  | static void get_word(char *buf, int buf_size, const char **pp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     get_word_until_chars(buf, buf_size, SPACE_CHARS, pp); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */ | 
					
						
							| 
									
										
										
										
											2010-01-07 22:44:03 +00:00
										 |  |  | static int sdp_parse_rtpmap(AVFormatContext *s, | 
					
						
							|  |  |  |                             AVCodecContext *codec, RTSPStream *rtsp_st, | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                             int payload_type, const char *p) | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     char buf[256]; | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     AVCodec *c; | 
					
						
							| 
									
										
										
										
											2006-06-18 11:33:14 +00:00
										 |  |  |     const char *c_name; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |     /* Loop into AVRtpDynamicPayloadTypes[] and AVRtpPayloadTypes[] and
 | 
					
						
							| 
									
										
										
										
											2010-01-13 15:55:42 +00:00
										 |  |  |      * see if we can handle this kind of payload. | 
					
						
							|  |  |  |      * The space should normally not be there but some Real streams or | 
					
						
							|  |  |  |      * particular servers ("RealServer Version 6.1.3.970", see issue 1658) | 
					
						
							|  |  |  |      * have a trailing space. */ | 
					
						
							|  |  |  |     get_word_sep(buf, sizeof(buf), "/ ", &p); | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |     if (payload_type >= RTP_PT_PRIVATE) { | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         RTPDynamicProtocolHandler *handler; | 
					
						
							|  |  |  |         for (handler = RTPFirstDynamicPayloadHandler; | 
					
						
							|  |  |  |              handler; handler = handler->next) { | 
					
						
							|  |  |  |             if (!strcasecmp(buf, handler->enc_name) && | 
					
						
							|  |  |  |                 codec->codec_type == handler->codec_type) { | 
					
						
							|  |  |  |                 codec->codec_id          = handler->codec_id; | 
					
						
							|  |  |  |                 rtsp_st->dynamic_handler = handler; | 
					
						
							|  |  |  |                 if (handler->open) | 
					
						
							|  |  |  |                     rtsp_st->dynamic_protocol_context = handler->open(); | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2006-10-26 18:36:03 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         /* We are in a standard case
 | 
					
						
							|  |  |  |          * (from http://www.iana.org/assignments/rtp-parameters). */
 | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |         /* search into AVRtpPayloadTypes[] */ | 
					
						
							| 
									
										
										
										
											2007-11-16 07:59:41 +00:00
										 |  |  |         codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type); | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     c = avcodec_find_decoder(codec->codec_id); | 
					
						
							|  |  |  |     if (c && c->name) | 
					
						
							| 
									
										
										
										
											2006-06-18 11:33:14 +00:00
										 |  |  |         c_name = c->name; | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2010-02-10 18:30:55 +00:00
										 |  |  |         c_name = "(null)"; | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-10 18:31:47 +00:00
										 |  |  |     get_word_sep(buf, sizeof(buf), "/", &p); | 
					
						
							|  |  |  |     i = atoi(buf); | 
					
						
							|  |  |  |     switch (codec->codec_type) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     case AVMEDIA_TYPE_AUDIO: | 
					
						
							| 
									
										
										
										
											2010-02-10 18:31:47 +00:00
										 |  |  |         av_log(s, AV_LOG_DEBUG, "audio codec set to: %s\n", c_name); | 
					
						
							|  |  |  |         codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE; | 
					
						
							|  |  |  |         codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS; | 
					
						
							|  |  |  |         if (i > 0) { | 
					
						
							|  |  |  |             codec->sample_rate = i; | 
					
						
							|  |  |  |             get_word_sep(buf, sizeof(buf), "/", &p); | 
					
						
							|  |  |  |             i = atoi(buf); | 
					
						
							|  |  |  |             if (i > 0) | 
					
						
							|  |  |  |                 codec->channels = i; | 
					
						
							|  |  |  |             // TODO: there is a bug here; if it is a mono stream, and
 | 
					
						
							|  |  |  |             // less than 22000Hz, faad upconverts to stereo and twice
 | 
					
						
							|  |  |  |             // the frequency.  No problem, but the sample rate is being
 | 
					
						
							|  |  |  |             // set here by the sdp line. Patch on its way. (rdm)
 | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-02-10 18:31:47 +00:00
										 |  |  |         av_log(s, AV_LOG_DEBUG, "audio samplerate set to: %i\n", | 
					
						
							|  |  |  |                codec->sample_rate); | 
					
						
							|  |  |  |         av_log(s, AV_LOG_DEBUG, "audio channels set to: %i\n", | 
					
						
							|  |  |  |                codec->channels); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     case AVMEDIA_TYPE_VIDEO: | 
					
						
							| 
									
										
										
										
											2010-02-10 18:31:47 +00:00
										 |  |  |         av_log(s, AV_LOG_DEBUG, "video codec set to: %s\n", c_name); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-29 19:17:49 +00:00
										 |  |  | /* parse the attribute line from the fmtp a line of an sdp response. This
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |  * is broken out as a function because it is used in rtp_h264.c, which is | 
					
						
							|  |  |  |  * forthcoming. */ | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  | int ff_rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, | 
					
						
							| 
									
										
										
										
											2010-02-23 11:05:36 +00:00
										 |  |  |                                 char *value, int value_size) | 
					
						
							| 
									
										
										
										
											2006-10-29 10:58:51 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |     *p += strspn(*p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     if (**p) { | 
					
						
							| 
									
										
										
										
											2006-10-29 10:58:51 +00:00
										 |  |  |         get_word_sep(attr, attr_size, "=", p); | 
					
						
							|  |  |  |         if (**p == '=') | 
					
						
							|  |  |  |             (*p)++; | 
					
						
							|  |  |  |         get_word_sep(value, value_size, ";", p); | 
					
						
							|  |  |  |         if (**p == ';') | 
					
						
							|  |  |  |             (*p)++; | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-01 12:29:22 +00:00
										 |  |  | /** Parse a string p in the form of Range:npt=xx-xx, and determine the start
 | 
					
						
							| 
									
										
										
										
											2006-11-06 21:58:43 +00:00
										 |  |  |  *  and end time. | 
					
						
							|  |  |  |  *  Used for seeking in the rtp stream. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char buf[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |     p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     if (!av_stristart(p, "npt=", &p)) | 
					
						
							| 
									
										
										
										
											2006-11-06 21:58:43 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *start = AV_NOPTS_VALUE; | 
					
						
							|  |  |  |     *end = AV_NOPTS_VALUE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get_word_sep(buf, sizeof(buf), "-", &p); | 
					
						
							|  |  |  |     *start = parse_date(buf, 1); | 
					
						
							|  |  |  |     if (*p == '-') { | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |         get_word_sep(buf, sizeof(buf), "-", &p); | 
					
						
							|  |  |  |         *end = parse_date(buf, 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | //    av_log(NULL, AV_LOG_DEBUG, "Range Start: %lld\n", *start);
 | 
					
						
							|  |  |  | //    av_log(NULL, AV_LOG_DEBUG, "Range End: %lld\n", *end);
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  | static int get_sockaddr(const char *buf, struct sockaddr_storage *sock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct addrinfo hints, *ai = NULL; | 
					
						
							|  |  |  |     memset(&hints, 0, sizeof(hints)); | 
					
						
							|  |  |  |     hints.ai_flags = AI_NUMERICHOST; | 
					
						
							|  |  |  |     if (getaddrinfo(buf, NULL, &hints, &ai)) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen)); | 
					
						
							|  |  |  |     freeaddrinfo(ai); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | typedef struct SDPParseState { | 
					
						
							|  |  |  |     /* SDP only */ | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |     struct sockaddr_storage default_ip; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     int            default_ttl; | 
					
						
							|  |  |  |     int            skip_media;  ///< set if an unknown m= line occurs
 | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | } SDPParseState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                            int letter, const char *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     char buf1[64], st_type[64]; | 
					
						
							|  |  |  |     const char *p; | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |     enum AVMediaType codec_type; | 
					
						
							| 
									
										
										
										
											2008-10-02 16:03:00 +00:00
										 |  |  |     int payload_type, i; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     AVStream *st; | 
					
						
							|  |  |  |     RTSPStream *rtsp_st; | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |     struct sockaddr_storage sdp_ip; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     int ttl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  |     dprintf(s, "sdp: %c='%s'\n", letter, buf); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     p = buf; | 
					
						
							| 
									
										
										
										
											2009-01-24 04:56:18 +00:00
										 |  |  |     if (s1->skip_media && letter != 'm') | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     switch (letter) { | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     case 'c': | 
					
						
							|  |  |  |         get_word(buf1, sizeof(buf1), &p); | 
					
						
							|  |  |  |         if (strcmp(buf1, "IN") != 0) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         get_word(buf1, sizeof(buf1), &p); | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |         if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6")) | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |             return; | 
					
						
							|  |  |  |         get_word_sep(buf1, sizeof(buf1), "/", &p); | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |         if (get_sockaddr(buf1, &sdp_ip)) | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |             return; | 
					
						
							|  |  |  |         ttl = 16; | 
					
						
							|  |  |  |         if (*p == '/') { | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |             get_word_sep(buf1, sizeof(buf1), "/", &p); | 
					
						
							|  |  |  |             ttl = atoi(buf1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (s->nb_streams == 0) { | 
					
						
							|  |  |  |             s1->default_ip = sdp_ip; | 
					
						
							|  |  |  |             s1->default_ttl = ttl; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             st = s->streams[s->nb_streams - 1]; | 
					
						
							|  |  |  |             rtsp_st = st->priv_data; | 
					
						
							|  |  |  |             rtsp_st->sdp_ip = sdp_ip; | 
					
						
							|  |  |  |             rtsp_st->sdp_ttl = ttl; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     case 's': | 
					
						
							| 
									
										
										
										
											2010-04-25 14:27:42 +00:00
										 |  |  |         av_metadata_set2(&s->metadata, "title", p, 0); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 'i': | 
					
						
							|  |  |  |         if (s->nb_streams == 0) { | 
					
						
							| 
									
										
										
										
											2010-04-25 14:27:42 +00:00
										 |  |  |             av_metadata_set2(&s->metadata, "comment", p, 0); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 'm': | 
					
						
							|  |  |  |         /* new stream */ | 
					
						
							| 
									
										
										
										
											2009-01-24 04:56:18 +00:00
										 |  |  |         s1->skip_media = 0; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         get_word(st_type, sizeof(st_type), &p); | 
					
						
							|  |  |  |         if (!strcmp(st_type, "audio")) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             codec_type = AVMEDIA_TYPE_AUDIO; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } else if (!strcmp(st_type, "video")) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             codec_type = AVMEDIA_TYPE_VIDEO; | 
					
						
							| 
									
										
										
										
											2009-03-03 16:48:56 +00:00
										 |  |  |         } else if (!strcmp(st_type, "application")) { | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |             codec_type = AVMEDIA_TYPE_DATA; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2009-01-24 04:56:18 +00:00
										 |  |  |             s1->skip_media = 1; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         rtsp_st = av_mallocz(sizeof(RTSPStream)); | 
					
						
							|  |  |  |         if (!rtsp_st) | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |         rtsp_st->stream_index = -1; | 
					
						
							|  |  |  |         dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         rtsp_st->sdp_ip = s1->default_ip; | 
					
						
							|  |  |  |         rtsp_st->sdp_ttl = s1->default_ttl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         get_word(buf1, sizeof(buf1), &p); /* port */ | 
					
						
							|  |  |  |         rtsp_st->sdp_port = atoi(buf1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |         /* XXX: handle list of formats */ | 
					
						
							|  |  |  |         get_word(buf1, sizeof(buf1), &p); /* format list */ | 
					
						
							|  |  |  |         rtsp_st->sdp_payload_type = atoi(buf1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-16 07:59:41 +00:00
										 |  |  |         if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |             /* no corresponding stream */ | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             st = av_new_stream(s, 0); | 
					
						
							|  |  |  |             if (!st) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             st->priv_data = rtsp_st; | 
					
						
							|  |  |  |             rtsp_st->stream_index = st->index; | 
					
						
							| 
									
										
										
										
											2005-07-17 22:24:36 +00:00
										 |  |  |             st->codec->codec_type = codec_type; | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |             if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) { | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |                 /* if standard payload type, we can find the codec right now */ | 
					
						
							| 
									
										
										
										
											2009-02-17 08:12:51 +00:00
										 |  |  |                 ff_rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type); | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         /* put a default control url */ | 
					
						
							| 
									
										
										
										
											2010-01-22 16:04:15 +00:00
										 |  |  |         av_strlcpy(rtsp_st->control_url, rt->control_uri, | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                    sizeof(rtsp_st->control_url)); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 'a': | 
					
						
							| 
									
										
										
										
											2010-01-22 16:04:15 +00:00
										 |  |  |         if (av_strstart(p, "control:", &p)) { | 
					
						
							|  |  |  |             if (s->nb_streams == 0) { | 
					
						
							|  |  |  |                 if (!strncmp(p, "rtsp://", 7)) | 
					
						
							|  |  |  |                     av_strlcpy(rt->control_uri, p, | 
					
						
							|  |  |  |                                sizeof(rt->control_uri)); | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             char proto[32]; | 
					
						
							|  |  |  |             /* get the control url */ | 
					
						
							|  |  |  |             st = s->streams[s->nb_streams - 1]; | 
					
						
							|  |  |  |             rtsp_st = st->priv_data; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             /* XXX: may need to add full url resolution */ | 
					
						
							| 
									
										
										
										
											2010-06-27 14:16:46 +00:00
										 |  |  |             av_url_split(proto, sizeof(proto), NULL, 0, NULL, 0, | 
					
						
							| 
									
										
										
										
											2010-03-08 09:05:03 +00:00
										 |  |  |                          NULL, NULL, 0, p); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             if (proto[0] == '\0') { | 
					
						
							|  |  |  |                 /* relative control URL */ | 
					
						
							| 
									
										
										
										
											2010-01-22 16:04:15 +00:00
										 |  |  |                 if (rtsp_st->control_url[strlen(rtsp_st->control_url)-1]!='/') | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 av_strlcat(rtsp_st->control_url, "/", | 
					
						
							|  |  |  |                            sizeof(rtsp_st->control_url)); | 
					
						
							|  |  |  |                 av_strlcat(rtsp_st->control_url, p, | 
					
						
							|  |  |  |                            sizeof(rtsp_st->control_url)); | 
					
						
							|  |  |  |             } else | 
					
						
							|  |  |  |                 av_strlcpy(rtsp_st->control_url, p, | 
					
						
							|  |  |  |                            sizeof(rtsp_st->control_url)); | 
					
						
							| 
									
										
										
										
											2010-01-22 16:04:15 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-01-09 23:36:17 +00:00
										 |  |  |         } else if (av_strstart(p, "rtpmap:", &p) && s->nb_streams > 0) { | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |             /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |             get_word(buf1, sizeof(buf1), &p); | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |             payload_type = atoi(buf1); | 
					
						
							| 
									
										
										
										
											2009-01-09 23:36:17 +00:00
										 |  |  |             st = s->streams[s->nb_streams - 1]; | 
					
						
							| 
									
										
										
										
											2009-01-09 23:36:39 +00:00
										 |  |  |             rtsp_st = st->priv_data; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:44:03 +00:00
										 |  |  |             sdp_parse_rtpmap(s, st->codec, rtsp_st, payload_type, p); | 
					
						
							| 
									
										
										
										
											2010-06-25 08:00:05 +00:00
										 |  |  |         } else if (av_strstart(p, "fmtp:", &p) || | 
					
						
							|  |  |  |                    av_strstart(p, "framesize:", &p)) { | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |             /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ | 
					
						
							| 
									
										
										
										
											2006-10-29 10:58:51 +00:00
										 |  |  |             // let dynamic protocol handlers have a stab at the line.
 | 
					
						
							|  |  |  |             get_word(buf1, sizeof(buf1), &p); | 
					
						
							|  |  |  |             payload_type = atoi(buf1); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             for (i = 0; i < s->nb_streams; i++) { | 
					
						
							|  |  |  |                 st      = s->streams[i]; | 
					
						
							| 
									
										
										
										
											2006-10-29 10:58:51 +00:00
										 |  |  |                 rtsp_st = st->priv_data; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 if (rtsp_st->sdp_payload_type == payload_type && | 
					
						
							|  |  |  |                     rtsp_st->dynamic_handler && | 
					
						
							|  |  |  |                     rtsp_st->dynamic_handler->parse_sdp_a_line) | 
					
						
							|  |  |  |                     rtsp_st->dynamic_handler->parse_sdp_a_line(s, i, | 
					
						
							|  |  |  |                         rtsp_st->dynamic_protocol_context, buf); | 
					
						
							| 
									
										
										
										
											2006-10-29 10:58:51 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         } else if (av_strstart(p, "range:", &p)) { | 
					
						
							| 
									
										
										
										
											2006-11-06 21:58:43 +00:00
										 |  |  |             int64_t start, end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // this is so that seeking on a streamed file can work.
 | 
					
						
							|  |  |  |             rtsp_parse_range_npt(p, &start, &end); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             s->start_time = start; | 
					
						
							|  |  |  |             /* AV_NOPTS_VALUE means live broadcast (and can't seek) */ | 
					
						
							|  |  |  |             s->duration   = (end == AV_NOPTS_VALUE) ? | 
					
						
							|  |  |  |                             AV_NOPTS_VALUE : end - start; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:26:20 +00:00
										 |  |  |         } else if (av_strstart(p, "IsRealDataType:integer;",&p)) { | 
					
						
							|  |  |  |             if (atoi(p) == 1) | 
					
						
							|  |  |  |                 rt->transport = RTSP_TRANSPORT_RDT; | 
					
						
							| 
									
										
										
										
											2009-03-17 12:34:57 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             if (rt->server_type == RTSP_SERVER_WMS) | 
					
						
							|  |  |  |                 ff_wms_parse_sdp_a_line(s, p); | 
					
						
							|  |  |  |             if (s->nb_streams > 0) { | 
					
						
							| 
									
										
										
										
											2009-03-17 12:35:55 +00:00
										 |  |  |                 if (rt->server_type == RTSP_SERVER_REAL) | 
					
						
							|  |  |  |                     ff_real_parse_sdp_a_line(s, s->nb_streams - 1, p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 rtsp_st = s->streams[s->nb_streams - 1]->priv_data; | 
					
						
							|  |  |  |                 if (rtsp_st->dynamic_handler && | 
					
						
							|  |  |  |                     rtsp_st->dynamic_handler->parse_sdp_a_line) | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                     rtsp_st->dynamic_handler->parse_sdp_a_line(s, | 
					
						
							|  |  |  |                         s->nb_streams - 1, | 
					
						
							| 
									
										
										
										
											2009-03-17 12:35:55 +00:00
										 |  |  |                         rtsp_st->dynamic_protocol_context, buf); | 
					
						
							| 
									
										
										
										
											2009-03-17 12:34:57 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-10 09:35:32 +00:00
										 |  |  | static int sdp_parse(AVFormatContext *s, const char *content) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     int letter; | 
					
						
							| 
									
										
										
										
											2009-01-09 23:44:52 +00:00
										 |  |  |     /* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
 | 
					
						
							|  |  |  |      * contain long SDP lines containing complete ASF Headers (several | 
					
						
							|  |  |  |      * kB) or arrays of MDPR (RM stream descriptor) headers plus | 
					
						
							|  |  |  |      * "rulebooks" describing their properties. Therefore, the SDP line | 
					
						
							| 
									
										
										
										
											2009-04-14 13:22:40 +00:00
										 |  |  |      * buffer is large. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2010-06-14 08:23:59 +00:00
										 |  |  |      * The Vorbis FMTP line can be up to 16KB - see xiph_parse_sdp_line | 
					
						
							|  |  |  |      * in rtpdec_xiph.c. */ | 
					
						
							| 
									
										
										
										
											2009-04-14 13:22:40 +00:00
										 |  |  |     char buf[16384], *q; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     SDPParseState sdp_parse_state, *s1 = &sdp_parse_state; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     memset(s1, 0, sizeof(SDPParseState)); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     p = content; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         letter = *p; | 
					
						
							|  |  |  |         if (letter == '\0') | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |         if (*p != '=') | 
					
						
							|  |  |  |             goto next_line; | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |         /* get the content */ | 
					
						
							|  |  |  |         q = buf; | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  |         while (*p != '\n' && *p != '\r' && *p != '\0') { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             if ((q - buf) < sizeof(buf) - 1) | 
					
						
							|  |  |  |                 *q++ = *p; | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         *q = '\0'; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |         sdp_parse_line(s, s1, letter, buf); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     next_line: | 
					
						
							|  |  |  |         while (*p != '\n' && *p != '\0') | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |         if (*p == '\n') | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | /* close and free RTSP streams */ | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  | void ff_rtsp_close_streams(AVFormatContext *s) | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-02-19 23:10:19 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     RTSPStream *rtsp_st; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |         rtsp_st = rt->rtsp_streams[i]; | 
					
						
							|  |  |  |         if (rtsp_st) { | 
					
						
							|  |  |  |             if (rtsp_st->transport_priv) { | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |                 if (s->oformat) { | 
					
						
							|  |  |  |                     AVFormatContext *rtpctx = rtsp_st->transport_priv; | 
					
						
							|  |  |  |                     av_write_trailer(rtpctx); | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |                     if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { | 
					
						
							|  |  |  |                         uint8_t *ptr; | 
					
						
							|  |  |  |                         url_close_dyn_buf(rtpctx->pb, &ptr); | 
					
						
							|  |  |  |                         av_free(ptr); | 
					
						
							|  |  |  |                     } else { | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:36 +00:00
										 |  |  |                         url_fclose(rtpctx->pb); | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2010-02-22 21:20:30 +00:00
										 |  |  |                     av_metadata_free(&rtpctx->streams[0]->metadata); | 
					
						
							|  |  |  |                     av_metadata_free(&rtpctx->metadata); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |                     av_free(rtpctx->streams[0]); | 
					
						
							|  |  |  |                     av_free(rtpctx); | 
					
						
							|  |  |  |                 } else if (rt->transport == RTSP_TRANSPORT_RDT) | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |                     ff_rdt_parse_close(rtsp_st->transport_priv); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     rtp_parse_close(rtsp_st->transport_priv); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (rtsp_st->rtp_handle) | 
					
						
							|  |  |  |                 url_close(rtsp_st->rtp_handle); | 
					
						
							|  |  |  |             if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 rtsp_st->dynamic_handler->close( | 
					
						
							|  |  |  |                     rtsp_st->dynamic_protocol_context); | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     av_free(rt->rtsp_streams); | 
					
						
							|  |  |  |     if (rt->asf_ctx) { | 
					
						
							|  |  |  |         av_close_input_stream (rt->asf_ctx); | 
					
						
							|  |  |  |         rt->asf_ctx = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-11 08:33:04 +00:00
										 |  |  | static void *rtsp_rtp_mux_open(AVFormatContext *s, AVStream *st, | 
					
						
							|  |  |  |                                URLContext *handle) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-15 14:20:07 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |     AVFormatContext *rtpctx; | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  |     AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!rtp_format) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Allocate an AVFormatContext for each output stream */ | 
					
						
							|  |  |  |     rtpctx = avformat_alloc_context(); | 
					
						
							|  |  |  |     if (!rtpctx) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rtpctx->oformat = rtp_format; | 
					
						
							|  |  |  |     if (!av_new_stream(rtpctx, 0)) { | 
					
						
							|  |  |  |         av_free(rtpctx); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* Copy the max delay setting; the rtp muxer reads this. */ | 
					
						
							|  |  |  |     rtpctx->max_delay = s->max_delay; | 
					
						
							|  |  |  |     /* Copy other stream parameters. */ | 
					
						
							|  |  |  |     rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-15 14:20:07 +00:00
										 |  |  |     /* Set the synchronized start time. */ | 
					
						
							|  |  |  |     rtpctx->start_time_realtime = rt->start_time; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |     /* Remove the local codec, link to the original codec
 | 
					
						
							|  |  |  |      * context instead, to give the rtp muxer access to | 
					
						
							|  |  |  |      * codec parameters. */ | 
					
						
							|  |  |  |     av_free(rtpctx->streams[0]->codec); | 
					
						
							|  |  |  |     rtpctx->streams[0]->codec = st->codec; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |     if (handle) { | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:36 +00:00
										 |  |  |         url_fdopen(&rtpctx->pb, handle); | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |     } else | 
					
						
							|  |  |  |         url_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |     ret = av_write_header(rtpctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ret) { | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |         if (handle) { | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:36 +00:00
										 |  |  |             url_fclose(rtpctx->pb); | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             uint8_t *ptr; | 
					
						
							|  |  |  |             url_close_dyn_buf(rtpctx->pb, &ptr); | 
					
						
							|  |  |  |             av_free(ptr); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |         av_free(rtpctx->streams[0]); | 
					
						
							|  |  |  |         av_free(rtpctx); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Copy the RTP AVStream timebase back to the original AVStream */ | 
					
						
							|  |  |  |     st->time_base = rtpctx->streams[0]->time_base; | 
					
						
							|  |  |  |     return rtpctx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     AVStream *st = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* open the RTP context */ | 
					
						
							|  |  |  |     if (rtsp_st->stream_index >= 0) | 
					
						
							|  |  |  |         st = s->streams[rtsp_st->stream_index]; | 
					
						
							|  |  |  |     if (!st) | 
					
						
							|  |  |  |         s->ctx_flags |= AVFMTCTX_NOHEADER; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |     if (s->oformat) { | 
					
						
							|  |  |  |         rtsp_st->transport_priv = rtsp_rtp_mux_open(s, st, rtsp_st->rtp_handle); | 
					
						
							| 
									
										
										
										
											2010-03-29 19:17:49 +00:00
										 |  |  |         /* Ownership of rtp_handle is passed to the rtp mux context */ | 
					
						
							| 
									
										
										
										
											2010-02-22 15:46:56 +00:00
										 |  |  |         rtsp_st->rtp_handle = NULL; | 
					
						
							|  |  |  |     } else if (rt->transport == RTSP_TRANSPORT_RDT) | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |         rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, | 
					
						
							|  |  |  |                                             rtsp_st->dynamic_protocol_context, | 
					
						
							|  |  |  |                                             rtsp_st->dynamic_handler); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle, | 
					
						
							| 
									
										
										
										
											2010-06-25 08:02:50 +00:00
										 |  |  |                                          rtsp_st->sdp_payload_type); | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!rtsp_st->transport_priv) { | 
					
						
							|  |  |  |          return AVERROR(ENOMEM); | 
					
						
							|  |  |  |     } else if (rt->transport != RTSP_TRANSPORT_RDT) { | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         if (rtsp_st->dynamic_handler) { | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |             rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, | 
					
						
							|  |  |  |                                            rtsp_st->dynamic_protocol_context, | 
					
						
							|  |  |  |                                            rtsp_st->dynamic_handler); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 21:28:19 +00:00
										 |  |  | #if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER
 | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | static int rtsp_probe(AVProbeData *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (av_strstart(p->filename, "rtsp:", NULL)) | 
					
						
							|  |  |  |         return AVPROBE_SCORE_MAX; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  |     int v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     p = *pp; | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |     p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     v = strtol(p, (char **)&p, 10); | 
					
						
							|  |  |  |     if (*p == '-') { | 
					
						
							|  |  |  |         p++; | 
					
						
							|  |  |  |         *min_ptr = v; | 
					
						
							|  |  |  |         v = strtol(p, (char **)&p, 10); | 
					
						
							|  |  |  |         *max_ptr = v; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         *min_ptr = v; | 
					
						
							|  |  |  |         *max_ptr = v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     *pp = p; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* XXX: only one transport specification is parsed */ | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  | static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     char transport_protocol[16]; | 
					
						
							|  |  |  |     char profile[16]; | 
					
						
							|  |  |  |     char lower_transport[16]; | 
					
						
							|  |  |  |     char parameter[16]; | 
					
						
							|  |  |  |     RTSPTransportField *th; | 
					
						
							|  |  |  |     char buf[256]; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     reply->nb_transports = 0; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         if (*p == '\0') | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         th = &reply->transports[reply->nb_transports]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         get_word_sep(transport_protocol, sizeof(transport_protocol), | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                      "/", &p); | 
					
						
							| 
									
										
										
										
											2007-12-28 11:23:25 +00:00
										 |  |  |         if (!strcasecmp (transport_protocol, "rtp")) { | 
					
						
							| 
									
										
										
										
											2007-12-28 11:25:25 +00:00
										 |  |  |             get_word_sep(profile, sizeof(profile), "/;,", &p); | 
					
						
							|  |  |  |             lower_transport[0] = '\0'; | 
					
						
							|  |  |  |             /* rtp/avp/<protocol> */ | 
					
						
							|  |  |  |             if (*p == '/') { | 
					
						
							|  |  |  |                 get_word_sep(lower_transport, sizeof(lower_transport), | 
					
						
							|  |  |  |                              ";,", &p); | 
					
						
							| 
									
										
										
										
											2008-09-30 13:26:20 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             th->transport = RTSP_TRANSPORT_RTP; | 
					
						
							|  |  |  |         } else if (!strcasecmp (transport_protocol, "x-pn-tng") || | 
					
						
							|  |  |  |                    !strcasecmp (transport_protocol, "x-real-rdt")) { | 
					
						
							| 
									
										
										
										
											2007-12-28 11:25:25 +00:00
										 |  |  |             /* x-pn-tng/<protocol> */ | 
					
						
							| 
									
										
										
										
											2007-12-28 11:23:25 +00:00
										 |  |  |             get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p); | 
					
						
							|  |  |  |             profile[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:26:20 +00:00
										 |  |  |             th->transport = RTSP_TRANSPORT_RDT; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  |         if (!strcasecmp(lower_transport, "TCP")) | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |             th->lower_transport = RTSP_LOWER_TRANSPORT_TCP; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |             th->lower_transport = RTSP_LOWER_TRANSPORT_UDP; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         if (*p == ';') | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |         /* get each parameter */ | 
					
						
							|  |  |  |         while (*p != '\0' && *p != ',') { | 
					
						
							|  |  |  |             get_word_sep(parameter, sizeof(parameter), "=;,", &p); | 
					
						
							|  |  |  |             if (!strcmp(parameter, "port")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							|  |  |  |                     rtsp_parse_range(&th->port_min, &th->port_max, &p); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else if (!strcmp(parameter, "client_port")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     rtsp_parse_range(&th->client_port_min, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                                      &th->client_port_max, &p); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else if (!strcmp(parameter, "server_port")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     rtsp_parse_range(&th->server_port_min, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                                      &th->server_port_max, &p); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else if (!strcmp(parameter, "interleaved")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |                     rtsp_parse_range(&th->interleaved_min, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                                      &th->interleaved_max, &p); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else if (!strcmp(parameter, "multicast")) { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |                 if (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP) | 
					
						
							|  |  |  |                     th->lower_transport = RTSP_LOWER_TRANSPORT_UDP_MULTICAST; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             } else if (!strcmp(parameter, "ttl")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							|  |  |  |                     th->ttl = strtol(p, (char **)&p, 10); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else if (!strcmp(parameter, "destination")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							|  |  |  |                     get_word_sep(buf, sizeof(buf), ";,", &p); | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:29 +00:00
										 |  |  |                     get_sockaddr(buf, &th->destination); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2010-09-03 19:25:59 +00:00
										 |  |  |             } else if (!strcmp(parameter, "source")) { | 
					
						
							|  |  |  |                 if (*p == '=') { | 
					
						
							|  |  |  |                     p++; | 
					
						
							|  |  |  |                     get_word_sep(buf, sizeof(buf), ";,", &p); | 
					
						
							|  |  |  |                     av_strlcpy(th->source, buf, sizeof(th->source)); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-09-03 19:25:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             while (*p != ';' && *p != '\0' && *p != ',') | 
					
						
							|  |  |  |                 p++; | 
					
						
							|  |  |  |             if (*p == ';') | 
					
						
							|  |  |  |                 p++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (*p == ',') | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         reply->nb_transports++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-25 21:48:58 +00:00
										 |  |  | void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, | 
					
						
							|  |  |  |                         HTTPAuthState *auth_state) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     const char *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* NOTE: we do case independent match for broken servers */ | 
					
						
							|  |  |  |     p = buf; | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     if (av_stristart(p, "Session:", &p)) { | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |         int t; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |         if (av_stristart(p, ";timeout=", &p) && | 
					
						
							|  |  |  |             (t = strtol(p, NULL, 10)) > 0) { | 
					
						
							|  |  |  |             reply->timeout = t; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     } else if (av_stristart(p, "Content-Length:", &p)) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         reply->content_length = strtol(p, NULL, 10); | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     } else if (av_stristart(p, "Transport:", &p)) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         rtsp_parse_transport(reply, p); | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     } else if (av_stristart(p, "CSeq:", &p)) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         reply->seq = strtol(p, NULL, 10); | 
					
						
							| 
									
										
										
										
											2007-06-24 11:27:12 +00:00
										 |  |  |     } else if (av_stristart(p, "Range:", &p)) { | 
					
						
							| 
									
										
										
										
											2006-11-06 21:58:43 +00:00
										 |  |  |         rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end); | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:02 +00:00
										 |  |  |     } else if (av_stristart(p, "RealChallenge1:", &p)) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:02 +00:00
										 |  |  |         av_strlcpy(reply->real_challenge, p, sizeof(reply->real_challenge)); | 
					
						
							| 
									
										
										
										
											2009-01-07 14:55:47 +00:00
										 |  |  |     } else if (av_stristart(p, "Server:", &p)) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2009-01-07 14:55:47 +00:00
										 |  |  |         av_strlcpy(reply->server, p, sizeof(reply->server)); | 
					
						
							| 
									
										
										
										
											2009-07-27 14:03:53 +00:00
										 |  |  |     } else if (av_stristart(p, "Notice:", &p) || | 
					
						
							|  |  |  |                av_stristart(p, "X-Notice:", &p)) { | 
					
						
							|  |  |  |         reply->notice = strtol(p, NULL, 10); | 
					
						
							| 
									
										
										
										
											2009-10-25 00:06:31 +00:00
										 |  |  |     } else if (av_stristart(p, "Location:", &p)) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2009-10-25 00:06:31 +00:00
										 |  |  |         av_strlcpy(reply->location, p , sizeof(reply->location)); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:48:58 +00:00
										 |  |  |     } else if (av_stristart(p, "WWW-Authenticate:", &p) && auth_state) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:48:58 +00:00
										 |  |  |         ff_http_auth_handle_header(auth_state, "WWW-Authenticate", p); | 
					
						
							|  |  |  |     } else if (av_stristart(p, "Authentication-Info:", &p) && auth_state) { | 
					
						
							| 
									
										
										
										
											2010-06-25 07:56:45 +00:00
										 |  |  |         p += strspn(p, SPACE_CHARS); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:48:58 +00:00
										 |  |  |         ff_http_auth_handle_header(auth_state, "Authentication-Info", p); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  | /* skip a RTP/TCP interleaved packet */ | 
					
						
							| 
									
										
										
										
											2010-03-15 16:31:15 +00:00
										 |  |  | void ff_rtsp_skip_packet(AVFormatContext *s) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     int ret, len, len1; | 
					
						
							|  |  |  |     uint8_t buf[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-04 06:25:53 +00:00
										 |  |  |     ret = url_read_complete(rt->rtsp_hd, buf, 3); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  |     if (ret != 3) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2007-07-06 09:32:34 +00:00
										 |  |  |     len = AV_RB16(buf + 1); | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     dprintf(s, "skipping RTP packet len=%d\n", len); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  |     /* skip payload */ | 
					
						
							|  |  |  |     while (len > 0) { | 
					
						
							|  |  |  |         len1 = len; | 
					
						
							|  |  |  |         if (len1 > sizeof(buf)) | 
					
						
							|  |  |  |             len1 = sizeof(buf); | 
					
						
							| 
									
										
										
										
											2009-06-04 06:25:53 +00:00
										 |  |  |         ret = url_read_complete(rt->rtsp_hd, buf, len1); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  |         if (ret != len1) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         len -= len1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  | int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, | 
					
						
							| 
									
										
										
										
											2010-02-23 11:05:36 +00:00
										 |  |  |                        unsigned char **content_ptr, | 
					
						
							|  |  |  |                        int return_on_interleaved_data) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     char buf[4096], buf1[1024], *q; | 
					
						
							|  |  |  |     unsigned char ch; | 
					
						
							|  |  |  |     const char *p; | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  |     int ret, content_length, line_count = 0; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     unsigned char *content = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-21 14:40:19 +00:00
										 |  |  |     memset(reply, 0, sizeof(*reply)); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* parse reply (XXX: use buffers) */ | 
					
						
							|  |  |  |     rt->last_reply[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         q = buf; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         for (;;) { | 
					
						
							| 
									
										
										
										
											2009-06-04 06:25:53 +00:00
										 |  |  |             ret = url_read_complete(rt->rtsp_hd, &ch, 1); | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  | #ifdef DEBUG_RTP_TCP
 | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  |             dprintf(s, "ret=%d c=%02x [%c]\n", ret, ch, ch); | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |             if (ret != 1) | 
					
						
							| 
									
										
										
										
											2010-08-25 13:42:17 +00:00
										 |  |  |                 return AVERROR_EOF; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             if (ch == '\n') | 
					
						
							|  |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  |             if (ch == '$') { | 
					
						
							|  |  |  |                 /* XXX: only parse it if first char on line ? */ | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  |                 if (return_on_interleaved_data) { | 
					
						
							|  |  |  |                     return 1; | 
					
						
							|  |  |  |                 } else | 
					
						
							| 
									
										
										
										
											2010-03-15 16:31:15 +00:00
										 |  |  |                     ff_rtsp_skip_packet(s); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  |             } else if (ch != '\r') { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                 if ((q - buf) < sizeof(buf) - 1) | 
					
						
							|  |  |  |                     *q++ = ch; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         *q = '\0'; | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         dprintf(s, "line='%s'\n", buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         /* test if last line */ | 
					
						
							|  |  |  |         if (buf[0] == '\0') | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         p = buf; | 
					
						
							|  |  |  |         if (line_count == 0) { | 
					
						
							|  |  |  |             /* get reply code */ | 
					
						
							|  |  |  |             get_word(buf1, sizeof(buf1), &p); | 
					
						
							|  |  |  |             get_word(buf1, sizeof(buf1), &p); | 
					
						
							|  |  |  |             reply->status_code = atoi(buf1); | 
					
						
							| 
									
										
										
										
											2010-08-06 10:26:30 +00:00
										 |  |  |             av_strlcpy(reply->reason, p, sizeof(reply->reason)); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:48:58 +00:00
										 |  |  |             ff_rtsp_parse_line(reply, p, &rt->auth_state); | 
					
						
							| 
									
										
										
										
											2007-06-23 23:10:32 +00:00
										 |  |  |             av_strlcat(rt->last_reply, p,    sizeof(rt->last_reply)); | 
					
						
							|  |  |  |             av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply)); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         line_count++; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') | 
					
						
							| 
									
										
										
										
											2007-06-23 23:10:32 +00:00
										 |  |  |         av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id)); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     content_length = reply->content_length; | 
					
						
							|  |  |  |     if (content_length > 0) { | 
					
						
							|  |  |  |         /* leave some room for a trailing '\0' (useful for simple parsing) */ | 
					
						
							|  |  |  |         content = av_malloc(content_length + 1); | 
					
						
							| 
									
										
										
										
											2009-06-04 06:25:53 +00:00
										 |  |  |         (void)url_read_complete(rt->rtsp_hd, content, content_length); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         content[content_length] = '\0'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (content_ptr) | 
					
						
							|  |  |  |         *content_ptr = content; | 
					
						
							| 
									
										
										
										
											2007-07-16 10:56:40 +00:00
										 |  |  |     else | 
					
						
							|  |  |  |         av_free(content); | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-24 22:38:48 +00:00
										 |  |  |     if (rt->seq != reply->seq) { | 
					
						
							|  |  |  |         av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n", | 
					
						
							|  |  |  |             rt->seq, reply->seq); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-27 14:03:53 +00:00
										 |  |  |     /* EOS */ | 
					
						
							|  |  |  |     if (reply->notice == 2101 /* End-of-Stream Reached */      || | 
					
						
							|  |  |  |         reply->notice == 2104 /* Start-of-Stream Reached */    || | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         reply->notice == 2306 /* Continuous Feed Terminated */) { | 
					
						
							| 
									
										
										
										
											2009-07-27 14:03:53 +00:00
										 |  |  |         rt->state = RTSP_STATE_IDLE; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     } else if (reply->notice >= 4400 && reply->notice < 5500) { | 
					
						
							| 
									
										
										
										
											2009-07-27 14:03:53 +00:00
										 |  |  |         return AVERROR(EIO); /* data or server error */ | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     } else if (reply->notice == 2401 /* Ticket Expired */ || | 
					
						
							| 
									
										
										
										
											2009-07-27 14:03:53 +00:00
										 |  |  |              (reply->notice >= 5500 && reply->notice < 5600) /* end of term */ ) | 
					
						
							|  |  |  |         return AVERROR(EPERM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  | int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s, | 
					
						
							| 
									
										
										
										
											2010-06-05 19:49:55 +00:00
										 |  |  |                                         const char *method, const char *url, | 
					
						
							|  |  |  |                                         const char *headers, | 
					
						
							|  |  |  |                                         const unsigned char *send_content, | 
					
						
							|  |  |  |                                         int send_content_length) | 
					
						
							| 
									
										
										
										
											2009-03-04 00:57:37 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     char buf[4096], *out_buf; | 
					
						
							|  |  |  |     char base64buf[AV_BASE64_SIZE(sizeof(buf))]; | 
					
						
							| 
									
										
										
										
											2009-03-04 00:57:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     /* Add in RTSP headers */ | 
					
						
							|  |  |  |     out_buf = buf; | 
					
						
							| 
									
										
										
										
											2009-03-04 00:57:37 +00:00
										 |  |  |     rt->seq++; | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |     snprintf(buf, sizeof(buf), "%s %s RTSP/1.0\r\n", method, url); | 
					
						
							|  |  |  |     if (headers) | 
					
						
							|  |  |  |         av_strlcat(buf, headers, sizeof(buf)); | 
					
						
							| 
									
										
										
										
											2010-03-25 22:04:41 +00:00
										 |  |  |     av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |     if (rt->session_id[0] != '\0' && (!headers || | 
					
						
							|  |  |  |         !strstr(headers, "\nIf-Match:"))) { | 
					
						
							| 
									
										
										
										
											2010-03-25 22:04:41 +00:00
										 |  |  |         av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id); | 
					
						
							| 
									
										
										
										
											2009-03-04 00:57:37 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-03-25 21:47:33 +00:00
										 |  |  |     if (rt->auth[0]) { | 
					
						
							|  |  |  |         char *str = ff_http_auth_create_response(&rt->auth_state, | 
					
						
							|  |  |  |                                                  rt->auth, url, method); | 
					
						
							|  |  |  |         if (str) | 
					
						
							|  |  |  |             av_strlcat(buf, str, sizeof(buf)); | 
					
						
							|  |  |  |         av_free(str); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-02-17 19:24:02 +00:00
										 |  |  |     if (send_content_length > 0 && send_content) | 
					
						
							|  |  |  |         av_strlcatf(buf, sizeof(buf), "Content-Length: %d\r\n", send_content_length); | 
					
						
							| 
									
										
										
										
											2009-03-04 00:57:37 +00:00
										 |  |  |     av_strlcat(buf, "\r\n", sizeof(buf)); | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     /* base64 encode rtsp if tunneling */ | 
					
						
							|  |  |  |     if (rt->control_transport == RTSP_MODE_TUNNEL) { | 
					
						
							|  |  |  |         av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf)); | 
					
						
							|  |  |  |         out_buf = base64buf; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  |     dprintf(s, "Sending:\n%s--\n", buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     url_write(rt->rtsp_hd_out, out_buf, strlen(out_buf)); | 
					
						
							|  |  |  |     if (send_content_length > 0 && send_content) { | 
					
						
							|  |  |  |         if (rt->control_transport == RTSP_MODE_TUNNEL) { | 
					
						
							|  |  |  |             av_log(s, AV_LOG_ERROR, "tunneling of RTSP requests " | 
					
						
							|  |  |  |                                     "with content data not supported\n"); | 
					
						
							|  |  |  |             return AVERROR_PATCHWELCOME; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-06-05 19:41:43 +00:00
										 |  |  |         url_write(rt->rtsp_hd_out, send_content, send_content_length); | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |     rt->last_cmd_time = av_gettime(); | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  | int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method, | 
					
						
							| 
									
										
										
										
											2010-06-05 19:49:55 +00:00
										 |  |  |                            const char *url, const char *headers) | 
					
						
							| 
									
										
										
										
											2010-02-17 19:24:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |     return ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0); | 
					
						
							| 
									
										
										
										
											2010-02-17 19:24:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  | int ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url, | 
					
						
							| 
									
										
										
										
											2010-06-05 19:49:55 +00:00
										 |  |  |                      const char *headers, RTSPMessageHeader *reply, | 
					
						
							|  |  |  |                      unsigned char **content_ptr) | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |     return ff_rtsp_send_cmd_with_content(s, method, url, headers, reply, | 
					
						
							| 
									
										
										
										
											2010-06-05 19:49:55 +00:00
										 |  |  |                                          content_ptr, NULL, 0); | 
					
						
							| 
									
										
										
										
											2009-03-04 00:57:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  | int ff_rtsp_send_cmd_with_content(AVFormatContext *s, | 
					
						
							| 
									
										
										
										
											2010-06-05 19:49:55 +00:00
										 |  |  |                                   const char *method, const char *url, | 
					
						
							|  |  |  |                                   const char *header, | 
					
						
							|  |  |  |                                   RTSPMessageHeader *reply, | 
					
						
							|  |  |  |                                   unsigned char **content_ptr, | 
					
						
							|  |  |  |                                   const unsigned char *send_content, | 
					
						
							|  |  |  |                                   int send_content_length) | 
					
						
							| 
									
										
										
										
											2010-02-17 19:24:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:49:43 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     HTTPAuthType cur_auth_type; | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |     int ret; | 
					
						
							| 
									
										
										
										
											2010-03-25 21:49:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | retry: | 
					
						
							|  |  |  |     cur_auth_type = rt->auth_state.auth_type; | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |     if ((ret = ff_rtsp_send_cmd_with_content_async(s, method, url, header, | 
					
						
							| 
									
										
										
										
											2010-06-05 19:49:55 +00:00
										 |  |  |                                                    send_content, | 
					
						
							|  |  |  |                                                    send_content_length))) | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |         return ret; | 
					
						
							| 
									
										
										
										
											2010-02-17 19:24:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |     if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0) ) < 0) | 
					
						
							|  |  |  |         return ret; | 
					
						
							| 
									
										
										
										
											2010-03-25 21:49:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (reply->status_code == 401 && cur_auth_type == HTTP_AUTH_NONE && | 
					
						
							|  |  |  |         rt->auth_state.auth_type != HTTP_AUTH_NONE) | 
					
						
							|  |  |  |         goto retry; | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-12 10:17:20 +00:00
										 |  |  |     if (reply->status_code > 400){ | 
					
						
							| 
									
										
										
										
											2010-08-06 10:26:30 +00:00
										 |  |  |         av_log(s, AV_LOG_ERROR, "method %s failed: %d%s\n", | 
					
						
							| 
									
										
										
										
											2010-07-12 10:17:20 +00:00
										 |  |  |                method, | 
					
						
							| 
									
										
										
										
											2010-08-06 10:26:30 +00:00
										 |  |  |                reply->status_code, | 
					
						
							|  |  |  |                reply->reason); | 
					
						
							| 
									
										
										
										
											2010-07-12 10:17:20 +00:00
										 |  |  |         av_log(s, AV_LOG_DEBUG, "%s\n", rt->last_reply); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:45:46 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2010-02-17 19:24:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2010-03-30 15:50:57 +00:00
										 |  |  |  * @return 0 on success, <0 on error, 1 if protocol is unavailable. | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | static int make_setup_request(AVFormatContext *s, const char *host, int port, | 
					
						
							|  |  |  |                               int lower_transport, const char *real_challenge) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2009-03-03 16:52:35 +00:00
										 |  |  |     int rtx, j, i, err, interleave = 0; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     RTSPStream *rtsp_st; | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  |     RTSPMessageHeader reply1, *reply = &reply1; | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     char cmd[2048]; | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |     const char *trans_pref; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:26:20 +00:00
										 |  |  |     if (rt->transport == RTSP_TRANSPORT_RDT) | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |         trans_pref = "x-pn-tng"; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         trans_pref = "RTP/AVP"; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |     /* default timeout: 1 minute */ | 
					
						
							|  |  |  |     rt->timeout = 60; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     /* for each stream, make the setup request */ | 
					
						
							|  |  |  |     /* XXX: we assume the same server is used for the control of each
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |      * RTSP stream */ | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         char transport[2048]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-03 16:52:35 +00:00
										 |  |  |         /**
 | 
					
						
							|  |  |  |          * WMS serves all UDP data over a single connection, the RTX, which | 
					
						
							|  |  |  |          * isn't necessarily the first in the SDP but has to be the first | 
					
						
							|  |  |  |          * to be set up, else the second/third SETUP will fail with a 461. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         if (lower_transport == RTSP_LOWER_TRANSPORT_UDP && | 
					
						
							|  |  |  |              rt->server_type == RTSP_SERVER_WMS) { | 
					
						
							|  |  |  |             if (i == 0) { | 
					
						
							|  |  |  |                 /* rtx first */ | 
					
						
							|  |  |  |                 for (rtx = 0; rtx < rt->nb_rtsp_streams; rtx++) { | 
					
						
							|  |  |  |                     int len = strlen(rt->rtsp_streams[rtx]->control_url); | 
					
						
							|  |  |  |                     if (len >= 4 && | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                         !strcmp(rt->rtsp_streams[rtx]->control_url + len - 4, | 
					
						
							|  |  |  |                                 "/rtx")) | 
					
						
							| 
									
										
										
										
											2009-03-03 16:52:35 +00:00
										 |  |  |                         break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (rtx == rt->nb_rtsp_streams) | 
					
						
							|  |  |  |                     return -1; /* no RTX found */ | 
					
						
							|  |  |  |                 rtsp_st = rt->rtsp_streams[rtx]; | 
					
						
							|  |  |  |             } else | 
					
						
							|  |  |  |                 rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1]; | 
					
						
							|  |  |  |         } else | 
					
						
							| 
									
										
										
										
											2009-03-03 16:53:04 +00:00
										 |  |  |             rtsp_st = rt->rtsp_streams[i]; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* RTP/UDP */ | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) { | 
					
						
							| 
									
										
										
										
											2002-07-24 17:40:26 +00:00
										 |  |  |             char buf[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-03 16:52:35 +00:00
										 |  |  |             if (rt->server_type == RTSP_SERVER_WMS && i > 1) { | 
					
						
							|  |  |  |                 port = reply->transports[0].client_port_min; | 
					
						
							|  |  |  |                 goto have_port; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-24 17:40:26 +00:00
										 |  |  |             /* first try in specified port range */ | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  |             if (RTSP_RTP_PORT_MIN != 0) { | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 while (j <= RTSP_RTP_PORT_MAX) { | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |                     ff_url_join(buf, sizeof(buf), "rtp", NULL, host, -1, | 
					
						
							|  |  |  |                                 "?localport=%d", j); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                     /* we will use two ports per rtp stream (rtp and rtcp) */ | 
					
						
							|  |  |  |                     j += 2; | 
					
						
							|  |  |  |                     if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) | 
					
						
							| 
									
										
										
										
											2002-07-24 17:40:26 +00:00
										 |  |  |                         goto rtp_opened; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2002-07-24 17:40:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | #if 0
 | 
					
						
							|  |  |  |             /* then try on any port */ | 
					
						
							|  |  |  |             if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { | 
					
						
							|  |  |  |                 err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-24 17:40:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         rtp_opened: | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |             port = rtp_get_local_port(rtsp_st->rtp_handle); | 
					
						
							| 
									
										
										
										
											2009-03-03 16:52:35 +00:00
										 |  |  |         have_port: | 
					
						
							| 
									
										
										
										
											2008-09-03 04:47:44 +00:00
										 |  |  |             snprintf(transport, sizeof(transport) - 1, | 
					
						
							| 
									
										
										
										
											2008-09-30 13:20:23 +00:00
										 |  |  |                      "%s/UDP;", trans_pref); | 
					
						
							|  |  |  |             if (rt->server_type != RTSP_SERVER_REAL) | 
					
						
							|  |  |  |                 av_strlcat(transport, "unicast;", sizeof(transport)); | 
					
						
							|  |  |  |             av_strlcatf(transport, sizeof(transport), | 
					
						
							|  |  |  |                      "client_port=%d", port); | 
					
						
							| 
									
										
										
										
											2009-03-03 16:52:35 +00:00
										 |  |  |             if (rt->transport == RTSP_TRANSPORT_RTP && | 
					
						
							|  |  |  |                 !(rt->server_type == RTSP_SERVER_WMS && i > 0)) | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |                 av_strlcatf(transport, sizeof(transport), "-%d", port + 1); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* RTP/TCP */ | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) { | 
					
						
							| 
									
										
										
										
											2009-03-03 16:48:56 +00:00
										 |  |  |             /** For WMS streams, the application streams are only used for
 | 
					
						
							|  |  |  |              * UDP. When trying to set it up for TCP streams, the server | 
					
						
							|  |  |  |              * will return an error. Therefore, we skip those streams. */ | 
					
						
							|  |  |  |             if (rt->server_type == RTSP_SERVER_WMS && | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 s->streams[rtsp_st->stream_index]->codec->codec_type == | 
					
						
							| 
									
										
										
										
											2010-03-30 23:30:55 +00:00
										 |  |  |                     AVMEDIA_TYPE_DATA) | 
					
						
							| 
									
										
										
										
											2009-03-03 16:48:56 +00:00
										 |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2008-09-03 04:47:44 +00:00
										 |  |  |             snprintf(transport, sizeof(transport) - 1, | 
					
						
							| 
									
										
										
										
											2009-02-01 13:37:45 +00:00
										 |  |  |                      "%s/TCP;", trans_pref); | 
					
						
							|  |  |  |             if (rt->server_type == RTSP_SERVER_WMS) | 
					
						
							|  |  |  |                 av_strlcat(transport, "unicast;", sizeof(transport)); | 
					
						
							|  |  |  |             av_strlcatf(transport, sizeof(transport), | 
					
						
							|  |  |  |                         "interleaved=%d-%d", | 
					
						
							|  |  |  |                         interleave, interleave + 1); | 
					
						
							|  |  |  |             interleave += 2; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) { | 
					
						
							| 
									
										
										
										
											2008-09-03 04:47:44 +00:00
										 |  |  |             snprintf(transport, sizeof(transport) - 1, | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |                      "%s/UDP;multicast", trans_pref); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-02-19 23:11:59 +00:00
										 |  |  |         if (s->oformat) { | 
					
						
							|  |  |  |             av_strlcat(transport, ";mode=receive", sizeof(transport)); | 
					
						
							|  |  |  |         } else if (rt->server_type == RTSP_SERVER_REAL || | 
					
						
							| 
									
										
										
										
											2010-02-22 16:11:38 +00:00
										 |  |  |                    rt->server_type == RTSP_SERVER_WMS) | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |             av_strlcat(transport, ";mode=play", sizeof(transport)); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         snprintf(cmd, sizeof(cmd), | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  |                  "Transport: %s\r\n", | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |                  transport); | 
					
						
							| 
									
										
										
										
											2008-09-14 13:55:21 +00:00
										 |  |  |         if (i == 0 && rt->server_type == RTSP_SERVER_REAL) { | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |             char real_res[41], real_csum[9]; | 
					
						
							|  |  |  |             ff_rdt_calc_response_and_checksum(real_res, real_csum, | 
					
						
							|  |  |  |                                               real_challenge); | 
					
						
							|  |  |  |             av_strlcatf(cmd, sizeof(cmd), | 
					
						
							|  |  |  |                         "If-Match: %s\r\n" | 
					
						
							|  |  |  |                         "RealChallenge2: %s, sd=%s\r\n", | 
					
						
							|  |  |  |                         rt->session_id, real_res, real_csum); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |         ff_rtsp_send_cmd(s, "SETUP", rtsp_st->control_url, cmd, reply, NULL); | 
					
						
							| 
									
										
										
										
											2008-03-19 14:05:08 +00:00
										 |  |  |         if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { | 
					
						
							|  |  |  |             err = 1; | 
					
						
							|  |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2008-03-19 14:08:16 +00:00
										 |  |  |         } else if (reply->status_code != RTSP_STATUS_OK || | 
					
						
							|  |  |  |                    reply->nb_transports != 1) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* XXX: same protocol for all streams is required */ | 
					
						
							|  |  |  |         if (i > 0) { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:26:20 +00:00
										 |  |  |             if (reply->transports[0].lower_transport != rt->lower_transport || | 
					
						
							|  |  |  |                 reply->transports[0].transport != rt->transport) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |                 err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |             rt->lower_transport = reply->transports[0].lower_transport; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:26:20 +00:00
										 |  |  |             rt->transport = reply->transports[0].transport; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-07 14:11:43 +00:00
										 |  |  |         /* close RTP connection if not chosen */ | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         if (reply->transports[0].lower_transport != RTSP_LOWER_TRANSPORT_UDP && | 
					
						
							|  |  |  |             (lower_transport == RTSP_LOWER_TRANSPORT_UDP)) { | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |             url_close(rtsp_st->rtp_handle); | 
					
						
							|  |  |  |             rtsp_st->rtp_handle = NULL; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         switch(reply->transports[0].lower_transport) { | 
					
						
							|  |  |  |         case RTSP_LOWER_TRANSPORT_TCP: | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             rtsp_st->interleaved_min = reply->transports[0].interleaved_min; | 
					
						
							|  |  |  |             rtsp_st->interleaved_max = reply->transports[0].interleaved_max; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         case RTSP_LOWER_TRANSPORT_UDP: { | 
					
						
							|  |  |  |             char url[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-03 19:25:59 +00:00
										 |  |  |             /* Use source address if specified */ | 
					
						
							|  |  |  |             if (reply->transports[0].source[0]) { | 
					
						
							|  |  |  |                 ff_url_join(url, sizeof(url), "rtp", NULL, | 
					
						
							|  |  |  |                             reply->transports[0].source, | 
					
						
							|  |  |  |                             reply->transports[0].server_port_min, NULL); | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |             ff_url_join(url, sizeof(url), "rtp", NULL, host, | 
					
						
							|  |  |  |                         reply->transports[0].server_port_min, NULL); | 
					
						
							| 
									
										
										
										
											2010-09-03 19:25:59 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && | 
					
						
							|  |  |  |                 rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { | 
					
						
							|  |  |  |                 err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-02-16 22:50:50 +00:00
										 |  |  |             /* Try to initialize the connection state in a
 | 
					
						
							|  |  |  |              * potential NAT router by sending dummy packets. | 
					
						
							|  |  |  |              * RTP/RTCP dummy packets are used for RDT, too. | 
					
						
							|  |  |  |              */ | 
					
						
							| 
									
										
										
										
											2010-02-19 23:13:21 +00:00
										 |  |  |             if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && s->iformat) | 
					
						
							| 
									
										
										
										
											2010-02-16 22:50:50 +00:00
										 |  |  |                 rtp_send_punch_packets(rtsp_st->rtp_handle); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:29 +00:00
										 |  |  |             char url[1024], namebuf[50]; | 
					
						
							|  |  |  |             struct sockaddr_storage addr; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             int port, ttl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:29 +00:00
										 |  |  |             if (reply->transports[0].destination.ss_family) { | 
					
						
							|  |  |  |                 addr      = reply->transports[0].destination; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 port      = reply->transports[0].port_min; | 
					
						
							|  |  |  |                 ttl       = reply->transports[0].ttl; | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:29 +00:00
										 |  |  |                 addr      = rtsp_st->sdp_ip; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |                 port      = rtsp_st->sdp_port; | 
					
						
							|  |  |  |                 ttl       = rtsp_st->sdp_ttl; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:29 +00:00
										 |  |  |             getnameinfo((struct sockaddr*) &addr, sizeof(addr), | 
					
						
							|  |  |  |                         namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); | 
					
						
							|  |  |  |             ff_url_join(url, sizeof(url), "rtp", NULL, namebuf, | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |                         port, "?ttl=%d", ttl); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { | 
					
						
							|  |  |  |                 err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |                 goto fail; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2005-05-26 07:47:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 17:43:04 +00:00
										 |  |  |         if ((err = rtsp_open_transport_ctx(s, rtsp_st))) | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |     if (reply->timeout > 0) | 
					
						
							|  |  |  |         rt->timeout = reply->timeout; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-14 13:55:21 +00:00
										 |  |  |     if (rt->server_type == RTSP_SERVER_REAL) | 
					
						
							| 
									
										
										
										
											2008-09-07 01:22:18 +00:00
										 |  |  |         rt->need_subscription = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | fail: | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2008-03-19 14:05:08 +00:00
										 |  |  |         if (rt->rtsp_streams[i]->rtp_handle) { | 
					
						
							|  |  |  |             url_close(rt->rtsp_streams[i]->rtp_handle); | 
					
						
							|  |  |  |             rt->rtsp_streams[i]->rtp_handle = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | static int rtsp_read_play(AVFormatContext *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     RTSPMessageHeader reply1, *reply = &reply1; | 
					
						
							| 
									
										
										
										
											2010-04-20 07:38:52 +00:00
										 |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |     char cmd[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state); | 
					
						
							| 
									
										
										
										
											2010-08-29 10:25:16 +00:00
										 |  |  |     rt->nb_byes = 0; | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) { | 
					
						
							|  |  |  |         if (rt->state == RTSP_STATE_PAUSED) { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |             cmd[0] = 0; | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             snprintf(cmd, sizeof(cmd), | 
					
						
							|  |  |  |                      "Range: npt=%0.3f-\r\n", | 
					
						
							|  |  |  |                      (double)rt->seek_timestamp / AV_TIME_BASE); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |         ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL); | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |         if (reply->status_code != RTSP_STATUS_OK) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-04-20 07:38:52 +00:00
										 |  |  |         if (reply->range_start != AV_NOPTS_VALUE && | 
					
						
							|  |  |  |             rt->transport == RTSP_TRANSPORT_RTP) { | 
					
						
							|  |  |  |             for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							|  |  |  |                 RTSPStream *rtsp_st = rt->rtsp_streams[i]; | 
					
						
							|  |  |  |                 RTPDemuxContext *rtpctx = rtsp_st->transport_priv; | 
					
						
							|  |  |  |                 AVStream *st = NULL; | 
					
						
							| 
									
										
										
										
											2010-05-19 09:46:29 +00:00
										 |  |  |                 if (!rtpctx) | 
					
						
							|  |  |  |                     continue; | 
					
						
							| 
									
										
										
										
											2010-04-20 07:38:52 +00:00
										 |  |  |                 if (rtsp_st->stream_index >= 0) | 
					
						
							|  |  |  |                     st = s->streams[rtsp_st->stream_index]; | 
					
						
							|  |  |  |                 rtpctx->last_rtcp_ntp_time  = AV_NOPTS_VALUE; | 
					
						
							|  |  |  |                 rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE; | 
					
						
							|  |  |  |                 if (st) | 
					
						
							|  |  |  |                     rtpctx->range_start_offset = av_rescale_q(reply->range_start, | 
					
						
							|  |  |  |                                                               AV_TIME_BASE_Q, | 
					
						
							|  |  |  |                                                               st->time_base); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-02-19 16:26:21 +00:00
										 |  |  |     rt->state = RTSP_STATE_STREAMING; | 
					
						
							| 
									
										
										
										
											2009-11-12 10:31:37 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 14:42:52 +00:00
										 |  |  | static int rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply) | 
					
						
							| 
									
										
										
										
											2010-02-19 23:21:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     char cmd[1024]; | 
					
						
							|  |  |  |     unsigned char *content = NULL; | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* describe the stream */ | 
					
						
							|  |  |  |     snprintf(cmd, sizeof(cmd), | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |              "Accept: application/sdp\r\n"); | 
					
						
							| 
									
										
										
										
											2010-02-19 23:21:44 +00:00
										 |  |  |     if (rt->server_type == RTSP_SERVER_REAL) { | 
					
						
							|  |  |  |         /**
 | 
					
						
							|  |  |  |          * The Require: attribute is needed for proper streaming from | 
					
						
							|  |  |  |          * Realmedia servers. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         av_strlcat(cmd, | 
					
						
							|  |  |  |                    "Require: com.real.retain-entity-for-setup\r\n", | 
					
						
							|  |  |  |                    sizeof(cmd)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |     ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content); | 
					
						
							| 
									
										
										
										
											2010-02-19 23:21:44 +00:00
										 |  |  |     if (!content) | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |     if (reply->status_code != RTSP_STATUS_OK) { | 
					
						
							|  |  |  |         av_freep(&content); | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* now we got the SDP description, we parse it */ | 
					
						
							|  |  |  |     ret = sdp_parse(s, (const char *)content); | 
					
						
							|  |  |  |     av_freep(&content); | 
					
						
							|  |  |  |     if (ret < 0) | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-11 08:24:18 +00:00
										 |  |  | static int rtsp_setup_output_streams(AVFormatContext *s, const char *addr) | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     RTSPMessageHeader reply1, *reply = &reply1; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     char *sdp; | 
					
						
							| 
									
										
										
										
											2010-03-11 08:24:18 +00:00
										 |  |  |     AVFormatContext sdp_ctx, *ctx_array[1]; | 
					
						
							| 
									
										
										
										
											2010-03-15 14:20:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     rt->start_time = av_gettime(); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Announce the stream */ | 
					
						
							| 
									
										
										
										
											2010-07-28 09:26:15 +00:00
										 |  |  |     sdp = av_mallocz(SDP_MAX_SIZE); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |     if (sdp == NULL) | 
					
						
							|  |  |  |         return AVERROR(ENOMEM); | 
					
						
							| 
									
										
										
										
											2010-03-11 08:24:18 +00:00
										 |  |  |     /* We create the SDP based on the RTSP AVFormatContext where we
 | 
					
						
							|  |  |  |      * aren't allowed to change the filename field. (We create the SDP | 
					
						
							|  |  |  |      * based on the RTSP context since the contexts for the RTP streams | 
					
						
							|  |  |  |      * don't exist yet.) In order to specify a custom URL with the actual | 
					
						
							|  |  |  |      * peer IP instead of the originally specified hostname, we create | 
					
						
							|  |  |  |      * a temporary copy of the AVFormatContext, where the custom URL is set. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * FIXME: Create the SDP without copying the AVFormatContext. | 
					
						
							|  |  |  |      * This either requires setting up the RTP stream AVFormatContexts | 
					
						
							|  |  |  |      * already here (complicating things immensely) or getting a more | 
					
						
							|  |  |  |      * flexible SDP creation interface. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     sdp_ctx = *s; | 
					
						
							|  |  |  |     ff_url_join(sdp_ctx.filename, sizeof(sdp_ctx.filename), | 
					
						
							|  |  |  |                 "rtsp", NULL, addr, -1, NULL); | 
					
						
							|  |  |  |     ctx_array[0] = &sdp_ctx; | 
					
						
							| 
									
										
										
										
											2010-07-28 09:26:15 +00:00
										 |  |  |     if (avf_sdp_create(ctx_array, 1, sdp, SDP_MAX_SIZE)) { | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |         av_free(sdp); | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     av_log(s, AV_LOG_INFO, "SDP:\n%s\n", sdp); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |     ff_rtsp_send_cmd_with_content(s, "ANNOUNCE", rt->control_uri, | 
					
						
							|  |  |  |                                   "Content-Type: application/sdp\r\n", | 
					
						
							|  |  |  |                                   reply, NULL, sdp, strlen(sdp)); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |     av_free(sdp); | 
					
						
							|  |  |  |     if (reply->status_code != RTSP_STATUS_OK) | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Set up the RTSPStreams for each AVStream */ | 
					
						
							|  |  |  |     for (i = 0; i < s->nb_streams; i++) { | 
					
						
							|  |  |  |         RTSPStream *rtsp_st; | 
					
						
							|  |  |  |         AVStream *st = s->streams[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rtsp_st = av_mallocz(sizeof(RTSPStream)); | 
					
						
							|  |  |  |         if (!rtsp_st) | 
					
						
							|  |  |  |             return AVERROR(ENOMEM); | 
					
						
							|  |  |  |         dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         st->priv_data = rtsp_st; | 
					
						
							|  |  |  |         rtsp_st->stream_index = i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-09 16:04:41 +00:00
										 |  |  |         av_strlcpy(rtsp_st->control_url, rt->control_uri, sizeof(rtsp_st->control_url)); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |         /* Note, this must match the relative uri set in the sdp content */ | 
					
						
							|  |  |  |         av_strlcatf(rtsp_st->control_url, sizeof(rtsp_st->control_url), | 
					
						
							|  |  |  |                     "/streamid=%d", i); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 19:41:43 +00:00
										 |  |  | void ff_rtsp_close_connections(AVFormatContext *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     if (rt->rtsp_hd_out != rt->rtsp_hd) url_close(rt->rtsp_hd_out); | 
					
						
							|  |  |  |     url_close(rt->rtsp_hd); | 
					
						
							| 
									
										
										
										
											2010-06-19 21:46:39 +00:00
										 |  |  |     rt->rtsp_hd = rt->rtsp_hd_out = NULL; | 
					
						
							| 
									
										
										
										
											2010-06-05 19:41:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  | int ff_rtsp_connect(AVFormatContext *s) | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2009-10-24 16:53:06 +00:00
										 |  |  |     char host[1024], path[1024], tcpname[1024], cmd[2048], auth[128]; | 
					
						
							|  |  |  |     char *option_list, *option, *filename; | 
					
						
							| 
									
										
										
										
											2010-03-09 14:59:40 +00:00
										 |  |  |     int port, err, tcp_fd; | 
					
						
							| 
									
										
										
										
											2010-07-21 17:27:28 +00:00
										 |  |  |     RTSPMessageHeader reply1 = {0}, *reply = &reply1; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     int lower_transport_mask = 0; | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:58 +00:00
										 |  |  |     char real_challenge[64]; | 
					
						
							| 
									
										
										
										
											2010-03-09 14:59:40 +00:00
										 |  |  |     struct sockaddr_storage peer; | 
					
						
							|  |  |  |     socklen_t peer_len = sizeof(peer); | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!ff_network_init()) | 
					
						
							|  |  |  |         return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | redirect: | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     rt->control_transport = RTSP_MODE_PLAIN; | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     /* extract hostname and port */ | 
					
						
							| 
									
										
										
										
											2010-06-27 14:16:46 +00:00
										 |  |  |     av_url_split(NULL, 0, auth, sizeof(auth), | 
					
						
							| 
									
										
										
										
											2010-03-08 09:05:03 +00:00
										 |  |  |                  host, sizeof(host), &port, path, sizeof(path), s->filename); | 
					
						
							| 
									
										
										
										
											2009-09-17 21:47:11 +00:00
										 |  |  |     if (*auth) { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:47:33 +00:00
										 |  |  |         av_strlcpy(rt->auth, auth, sizeof(rt->auth)); | 
					
						
							| 
									
										
										
										
											2009-09-17 21:47:11 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     if (port < 0) | 
					
						
							|  |  |  |         port = RTSP_DEFAULT_PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* search for options */ | 
					
						
							| 
									
										
										
										
											2010-03-23 07:59:23 +00:00
										 |  |  |     option_list = strrchr(path, '?'); | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     if (option_list) { | 
					
						
							| 
									
										
										
										
											2010-03-23 07:55:15 +00:00
										 |  |  |         /* Strip out the RTSP specific options, write out the rest of
 | 
					
						
							|  |  |  |          * the options back into the same string. */ | 
					
						
							|  |  |  |         filename = option_list; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         while (option_list) { | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |             /* move the option pointer */ | 
					
						
							| 
									
										
										
										
											2009-10-24 16:53:06 +00:00
										 |  |  |             option = ++option_list; | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |             option_list = strchr(option_list, '&'); | 
					
						
							|  |  |  |             if (option_list) | 
					
						
							| 
									
										
										
										
											2009-10-24 16:53:06 +00:00
										 |  |  |                 *option_list = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |             /* handle the options */ | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             if (!strcmp(option, "udp")) { | 
					
						
							| 
									
										
										
										
											2010-03-23 08:00:37 +00:00
										 |  |  |                 lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             } else if (!strcmp(option, "multicast")) { | 
					
						
							| 
									
										
										
										
											2010-03-23 08:00:37 +00:00
										 |  |  |                 lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             } else if (!strcmp(option, "tcp")) { | 
					
						
							| 
									
										
										
										
											2010-03-23 08:00:37 +00:00
										 |  |  |                 lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP); | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |             } else if(!strcmp(option, "http")) { | 
					
						
							|  |  |  |                 lower_transport_mask |= (1<< RTSP_LOWER_TRANSPORT_TCP); | 
					
						
							|  |  |  |                 rt->control_transport = RTSP_MODE_TUNNEL; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2010-03-23 07:55:15 +00:00
										 |  |  |                 /* Write options back into the buffer, using memmove instead
 | 
					
						
							|  |  |  |                  * of strcpy since the strings may overlap. */ | 
					
						
							|  |  |  |                 int len = strlen(option); | 
					
						
							|  |  |  |                 memmove(++filename, option, len); | 
					
						
							|  |  |  |                 filename += len; | 
					
						
							| 
									
										
										
										
											2009-10-24 16:53:06 +00:00
										 |  |  |                 if (option_list) *filename = '&'; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-24 16:53:06 +00:00
										 |  |  |         *filename = 0; | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     if (!lower_transport_mask) | 
					
						
							| 
									
										
										
										
											2009-02-16 16:27:35 +00:00
										 |  |  |         lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1; | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |     if (s->oformat) { | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |         /* Only UDP or TCP - UDP multicast isn't supported. */ | 
					
						
							|  |  |  |         lower_transport_mask &= (1 << RTSP_LOWER_TRANSPORT_UDP) | | 
					
						
							|  |  |  |                                 (1 << RTSP_LOWER_TRANSPORT_TCP); | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |         if (!lower_transport_mask || rt->control_transport == RTSP_MODE_TUNNEL) { | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |             av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, " | 
					
						
							| 
									
										
										
										
											2010-03-22 15:07:05 +00:00
										 |  |  |                                     "only UDP and TCP are supported for output.\n"); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |             err = AVERROR(EINVAL); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-25 22:21:09 +00:00
										 |  |  |     /* Construct the URI used in request; this is similar to s->filename,
 | 
					
						
							|  |  |  |      * but with authentication credentials removed and RTSP specific options | 
					
						
							|  |  |  |      * stripped out. */ | 
					
						
							|  |  |  |     ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL, | 
					
						
							|  |  |  |                 host, port, "%s", path); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     if (rt->control_transport == RTSP_MODE_TUNNEL) { | 
					
						
							|  |  |  |         /* set up initial handshake for tunneling */ | 
					
						
							|  |  |  |         char httpname[1024]; | 
					
						
							|  |  |  |         char sessioncookie[17]; | 
					
						
							|  |  |  |         char headers[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-19 21:57:45 +00:00
										 |  |  |         ff_url_join(httpname, sizeof(httpname), "http", auth, host, port, "%s", path); | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |         snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x", | 
					
						
							|  |  |  |                  av_get_random_seed(), av_get_random_seed()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* GET requests */ | 
					
						
							| 
									
										
										
										
											2010-06-22 14:15:00 +00:00
										 |  |  |         if (url_alloc(&rt->rtsp_hd, httpname, URL_RDONLY) < 0) { | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |             err = AVERROR(EIO); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* generate GET headers */ | 
					
						
							|  |  |  |         snprintf(headers, sizeof(headers), | 
					
						
							|  |  |  |                  "x-sessioncookie: %s\r\n" | 
					
						
							|  |  |  |                  "Accept: application/x-rtsp-tunnelled\r\n" | 
					
						
							|  |  |  |                  "Pragma: no-cache\r\n" | 
					
						
							|  |  |  |                  "Cache-Control: no-cache\r\n", | 
					
						
							|  |  |  |                  sessioncookie); | 
					
						
							| 
									
										
										
										
											2010-06-19 21:36:13 +00:00
										 |  |  |         ff_http_set_headers(rt->rtsp_hd, headers); | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* complete the connection */ | 
					
						
							| 
									
										
										
										
											2010-06-22 14:15:00 +00:00
										 |  |  |         if (url_connect(rt->rtsp_hd)) { | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |             err = AVERROR(EIO); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* POST requests */ | 
					
						
							| 
									
										
										
										
											2010-06-22 14:15:00 +00:00
										 |  |  |         if (url_alloc(&rt->rtsp_hd_out, httpname, URL_WRONLY) < 0 ) { | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |             err = AVERROR(EIO); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* generate POST headers */ | 
					
						
							|  |  |  |         snprintf(headers, sizeof(headers), | 
					
						
							|  |  |  |                  "x-sessioncookie: %s\r\n" | 
					
						
							|  |  |  |                  "Content-Type: application/x-rtsp-tunnelled\r\n" | 
					
						
							|  |  |  |                  "Pragma: no-cache\r\n" | 
					
						
							|  |  |  |                  "Cache-Control: no-cache\r\n" | 
					
						
							|  |  |  |                  "Content-Length: 32767\r\n" | 
					
						
							|  |  |  |                  "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n", | 
					
						
							|  |  |  |                  sessioncookie); | 
					
						
							| 
									
										
										
										
											2010-06-19 21:36:13 +00:00
										 |  |  |         ff_http_set_headers(rt->rtsp_hd_out, headers); | 
					
						
							|  |  |  |         ff_http_set_chunked_transfer_encoding(rt->rtsp_hd_out, 0); | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-21 19:41:02 +00:00
										 |  |  |         /* Initialize the authentication state for the POST session. The HTTP
 | 
					
						
							|  |  |  |          * protocol implementation doesn't properly handle multi-pass | 
					
						
							|  |  |  |          * authentication for POST requests, since it would require one of | 
					
						
							|  |  |  |          * the following: | 
					
						
							|  |  |  |          * - implementing Expect: 100-continue, which many HTTP servers | 
					
						
							|  |  |  |          *   don't support anyway, even less the RTSP servers that do HTTP | 
					
						
							|  |  |  |          *   tunneling | 
					
						
							|  |  |  |          * - sending the whole POST data until getting a 401 reply specifying | 
					
						
							|  |  |  |          *   what authentication method to use, then resending all that data | 
					
						
							|  |  |  |          * - waiting for potential 401 replies directly after sending the | 
					
						
							|  |  |  |          *   POST header (waiting for some unspecified time) | 
					
						
							|  |  |  |          * Therefore, we copy the full auth state, which works for both basic | 
					
						
							|  |  |  |          * and digest. (For digest, we would have to synchronize the nonce | 
					
						
							|  |  |  |          * count variable between the two sessions, if we'd do more requests | 
					
						
							|  |  |  |          * with the original session, though.) | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         ff_http_init_auth_state(rt->rtsp_hd_out, rt->rtsp_hd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-22 14:15:00 +00:00
										 |  |  |         /* complete the connection */ | 
					
						
							|  |  |  |         if (url_connect(rt->rtsp_hd_out)) { | 
					
						
							|  |  |  |             err = AVERROR(EIO); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2010-06-14 09:09:59 +00:00
										 |  |  |         /* open the tcp connection */ | 
					
						
							| 
									
										
										
										
											2010-06-14 08:12:40 +00:00
										 |  |  |         ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL); | 
					
						
							| 
									
										
										
										
											2010-06-19 21:36:13 +00:00
										 |  |  |         if (url_open(&rt->rtsp_hd, tcpname, URL_RDWR) < 0) { | 
					
						
							| 
									
										
										
										
											2010-06-14 08:12:40 +00:00
										 |  |  |             err = AVERROR(EIO); | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-06-19 21:36:13 +00:00
										 |  |  |         rt->rtsp_hd_out = rt->rtsp_hd; | 
					
						
							| 
									
										
										
										
											2010-06-08 12:40:34 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |     rt->seq = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-19 21:36:13 +00:00
										 |  |  |     tcp_fd = url_get_file_handle(rt->rtsp_hd); | 
					
						
							| 
									
										
										
										
											2010-03-09 14:59:40 +00:00
										 |  |  |     if (!getpeername(tcp_fd, (struct sockaddr*) &peer, &peer_len)) { | 
					
						
							|  |  |  |         getnameinfo((struct sockaddr*) &peer, peer_len, host, sizeof(host), | 
					
						
							|  |  |  |                     NULL, 0, NI_NUMERICHOST); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     /* request options supported by the server; this also detects server
 | 
					
						
							|  |  |  |      * type */ | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:58 +00:00
										 |  |  |     for (rt->server_type = RTSP_SERVER_RTP;;) { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |         cmd[0] = 0; | 
					
						
							| 
									
										
										
										
											2008-09-14 13:55:21 +00:00
										 |  |  |         if (rt->server_type == RTSP_SERVER_REAL) | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:58 +00:00
										 |  |  |             av_strlcat(cmd, | 
					
						
							|  |  |  |                        /**
 | 
					
						
							|  |  |  |                         * The following entries are required for proper | 
					
						
							|  |  |  |                         * streaming from a Realmedia server. They are | 
					
						
							|  |  |  |                         * interdependent in some way although we currently | 
					
						
							|  |  |  |                         * don't quite understand how. Values were copied | 
					
						
							|  |  |  |                         * from mplayer SVN r23589. | 
					
						
							|  |  |  |                         * @param CompanyID is a 16-byte ID in base64 | 
					
						
							|  |  |  |                         * @param ClientChallenge is a 16-byte ID in hex | 
					
						
							|  |  |  |                         */ | 
					
						
							|  |  |  |                        "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n" | 
					
						
							|  |  |  |                        "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n" | 
					
						
							|  |  |  |                        "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n" | 
					
						
							|  |  |  |                        "GUID: 00000000-0000-0000-0000-000000000000\r\n", | 
					
						
							|  |  |  |                        sizeof(cmd)); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |         ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL); | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:58 +00:00
										 |  |  |         if (reply->status_code != RTSP_STATUS_OK) { | 
					
						
							|  |  |  |             err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* detect server type if not standard-compliant RTP */ | 
					
						
							| 
									
										
										
										
											2008-09-14 13:55:21 +00:00
										 |  |  |         if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { | 
					
						
							|  |  |  |             rt->server_type = RTSP_SERVER_REAL; | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:58 +00:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2009-01-07 14:55:47 +00:00
										 |  |  |         } else if (!strncasecmp(reply->server, "WMServer/", 9)) { | 
					
						
							|  |  |  |             rt->server_type = RTSP_SERVER_WMS; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         } else if (rt->server_type == RTSP_SERVER_REAL) | 
					
						
							| 
									
										
										
										
											2008-08-31 17:32:58 +00:00
										 |  |  |             strcpy(real_challenge, reply->real_challenge); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |     if (s->iformat) | 
					
						
							| 
									
										
										
										
											2010-03-22 14:42:52 +00:00
										 |  |  |         err = rtsp_setup_input_streams(s, reply); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:56:18 +00:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2010-03-11 08:24:18 +00:00
										 |  |  |         err = rtsp_setup_output_streams(s, host); | 
					
						
							| 
									
										
										
										
											2010-02-19 23:21:44 +00:00
										 |  |  |     if (err) | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  |         goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-19 14:05:08 +00:00
										 |  |  |     do { | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         int lower_transport = ff_log2_tab[lower_transport_mask & | 
					
						
							|  |  |  |                                   ~(lower_transport_mask - 1)]; | 
					
						
							| 
									
										
										
										
											2008-03-19 14:05:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         err = make_setup_request(s, host, port, lower_transport, | 
					
						
							| 
									
										
										
										
											2008-09-14 13:55:21 +00:00
										 |  |  |                                  rt->server_type == RTSP_SERVER_REAL ? | 
					
						
							| 
									
										
										
										
											2008-09-03 04:44:58 +00:00
										 |  |  |                                      real_challenge : NULL); | 
					
						
							| 
									
										
										
										
											2008-03-19 14:05:08 +00:00
										 |  |  |         if (err < 0) | 
					
						
							| 
									
										
										
										
											2008-03-19 14:08:16 +00:00
										 |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |         lower_transport_mask &= ~(1 << lower_transport); | 
					
						
							|  |  |  |         if (lower_transport_mask == 0 && err == 1) { | 
					
						
							| 
									
										
										
										
											2010-04-16 00:20:11 +00:00
										 |  |  |             err = FF_NETERROR(EPROTONOSUPPORT); | 
					
						
							| 
									
										
										
										
											2008-03-19 14:05:08 +00:00
										 |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } while (err); | 
					
						
							| 
									
										
										
										
											2008-03-17 12:16:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |     rt->state = RTSP_STATE_IDLE; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     rt->seek_timestamp = 0; /* default is to start stream at position zero */ | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  |  fail: | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |     ff_rtsp_close_streams(s); | 
					
						
							| 
									
										
										
										
											2010-06-05 19:41:43 +00:00
										 |  |  |     ff_rtsp_close_connections(s); | 
					
						
							| 
									
										
										
										
											2010-02-22 15:57:40 +00:00
										 |  |  |     if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) { | 
					
						
							| 
									
										
										
										
											2009-10-25 00:06:31 +00:00
										 |  |  |         av_strlcpy(s->filename, reply->location, sizeof(s->filename)); | 
					
						
							|  |  |  |         av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", | 
					
						
							|  |  |  |                reply->status_code, | 
					
						
							|  |  |  |                s->filename); | 
					
						
							|  |  |  |         goto redirect; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |     ff_network_close(); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-02-22 21:28:19 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 21:28:19 +00:00
										 |  |  | #if CONFIG_RTSP_DEMUXER
 | 
					
						
							| 
									
										
										
										
											2010-02-19 23:23:40 +00:00
										 |  |  | static int rtsp_read_header(AVFormatContext *s, | 
					
						
							|  |  |  |                             AVFormatParameters *ap) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-09 23:00:13 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2010-02-19 23:23:40 +00:00
										 |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |     ret = ff_rtsp_connect(s); | 
					
						
							| 
									
										
										
										
											2010-02-19 23:23:40 +00:00
										 |  |  |     if (ret) | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-09 23:00:13 +00:00
										 |  |  |     rt->real_setup_cache = av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache)); | 
					
						
							|  |  |  |     if (!rt->real_setup_cache) | 
					
						
							|  |  |  |         return AVERROR(ENOMEM); | 
					
						
							|  |  |  |     rt->real_setup = rt->real_setup_cache + s->nb_streams * sizeof(*rt->real_setup); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-19 23:23:40 +00:00
										 |  |  |     if (ap->initial_pause) { | 
					
						
							|  |  |  |          /* do not start immediately */ | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |          if (rtsp_read_play(s) < 0) { | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |             ff_rtsp_close_streams(s); | 
					
						
							| 
									
										
										
										
											2010-06-05 19:41:43 +00:00
										 |  |  |             ff_rtsp_close_connections(s); | 
					
						
							| 
									
										
										
										
											2010-02-19 23:23:40 +00:00
										 |  |  |             return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  | static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, | 
					
						
							|  |  |  |                            uint8_t *buf, int buf_size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     RTSPStream *rtsp_st; | 
					
						
							|  |  |  |     fd_set rfds; | 
					
						
							| 
									
										
										
										
											2010-08-29 10:16:54 +00:00
										 |  |  |     int fd, fd_rtcp, fd_max, n, i, ret, tcp_fd, timeout_cnt = 0; | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |     struct timeval tv; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |         if (url_interrupt_cb()) | 
					
						
							|  |  |  |             return AVERROR(EINTR); | 
					
						
							|  |  |  |         FD_ZERO(&rfds); | 
					
						
							|  |  |  |         if (rt->rtsp_hd) { | 
					
						
							|  |  |  |             tcp_fd = fd_max = url_get_file_handle(rt->rtsp_hd); | 
					
						
							|  |  |  |             FD_SET(tcp_fd, &rfds); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             fd_max = 0; | 
					
						
							|  |  |  |             tcp_fd = -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |             rtsp_st = rt->rtsp_streams[i]; | 
					
						
							|  |  |  |             if (rtsp_st->rtp_handle) { | 
					
						
							|  |  |  |                 fd = url_get_file_handle(rtsp_st->rtp_handle); | 
					
						
							| 
									
										
										
										
											2010-08-29 10:16:54 +00:00
										 |  |  |                 fd_rtcp = rtp_get_rtcp_file_handle(rtsp_st->rtp_handle); | 
					
						
							|  |  |  |                 if (FFMAX(fd, fd_rtcp) > fd_max) | 
					
						
							|  |  |  |                     fd_max = FFMAX(fd, fd_rtcp); | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |                 FD_SET(fd, &rfds); | 
					
						
							| 
									
										
										
										
											2010-08-29 10:16:54 +00:00
										 |  |  |                 FD_SET(fd_rtcp, &rfds); | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         tv.tv_sec = 0; | 
					
						
							| 
									
										
										
										
											2010-03-29 17:36:08 +00:00
										 |  |  |         tv.tv_usec = SELECT_TIMEOUT_MS * 1000; | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |         n = select(fd_max + 1, &rfds, NULL, NULL, &tv); | 
					
						
							|  |  |  |         if (n > 0) { | 
					
						
							| 
									
										
										
										
											2010-03-29 17:36:08 +00:00
										 |  |  |             timeout_cnt = 0; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |             for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |                 rtsp_st = rt->rtsp_streams[i]; | 
					
						
							|  |  |  |                 if (rtsp_st->rtp_handle) { | 
					
						
							|  |  |  |                     fd = url_get_file_handle(rtsp_st->rtp_handle); | 
					
						
							| 
									
										
										
										
											2010-08-29 10:16:54 +00:00
										 |  |  |                     fd_rtcp = rtp_get_rtcp_file_handle(rtsp_st->rtp_handle); | 
					
						
							|  |  |  |                     if (FD_ISSET(fd_rtcp, &rfds) || FD_ISSET(fd, &rfds)) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |                         ret = url_read(rtsp_st->rtp_handle, buf, buf_size); | 
					
						
							|  |  |  |                         if (ret > 0) { | 
					
						
							|  |  |  |                             *prtsp_st = rtsp_st; | 
					
						
							|  |  |  |                             return ret; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | #if CONFIG_RTSP_DEMUXER
 | 
					
						
							| 
									
										
										
										
											2010-01-26 15:51:54 +00:00
										 |  |  |             if (tcp_fd != -1 && FD_ISSET(tcp_fd, &rfds)) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |                 RTSPMessageHeader reply; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-24 18:52:27 +00:00
										 |  |  |                 ret = ff_rtsp_read_reply(s, &reply, NULL, 0); | 
					
						
							|  |  |  |                 if (ret < 0) | 
					
						
							|  |  |  |                     return ret; | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |                 /* XXX: parse message */ | 
					
						
							| 
									
										
										
										
											2010-02-19 16:26:21 +00:00
										 |  |  |                 if (rt->state != RTSP_STATE_STREAMING) | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |                     return 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-03-29 17:36:08 +00:00
										 |  |  |         } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) { | 
					
						
							| 
									
										
										
										
											2010-04-15 18:27:27 +00:00
										 |  |  |             return FF_NETERROR(ETIMEDOUT); | 
					
						
							| 
									
										
										
										
											2010-03-29 17:36:08 +00:00
										 |  |  |         } else if (n < 0 && errno != EINTR) | 
					
						
							|  |  |  |             return AVERROR(errno); | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  | static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, | 
					
						
							|  |  |  |                            uint8_t *buf, int buf_size) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  |     int id, len, i, ret; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     RTSPStream *rtsp_st; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | #ifdef DEBUG_RTP_TCP
 | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  |     dprintf(s, "tcp_read_packet:\n"); | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | redo: | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  |         RTSPMessageHeader reply; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |         ret = ff_rtsp_read_reply(s, &reply, NULL, 1); | 
					
						
							| 
									
										
										
										
											2010-08-25 13:42:17 +00:00
										 |  |  |         if (ret < 0) | 
					
						
							|  |  |  |             return ret; | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  |         if (ret == 1) /* received '$' */ | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2009-03-21 20:46:36 +00:00
										 |  |  |         /* XXX: parse message */ | 
					
						
							| 
									
										
										
										
											2010-02-19 16:26:21 +00:00
										 |  |  |         if (rt->state != RTSP_STATE_STREAMING) | 
					
						
							| 
									
										
										
										
											2009-07-27 14:03:53 +00:00
										 |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-06-04 06:25:53 +00:00
										 |  |  |     ret = url_read_complete(rt->rtsp_hd, buf, 3); | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  |     if (ret != 3) | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     id  = buf[0]; | 
					
						
							| 
									
										
										
										
											2007-07-06 09:32:34 +00:00
										 |  |  |     len = AV_RB16(buf + 1); | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | #ifdef DEBUG_RTP_TCP
 | 
					
						
							| 
									
										
										
										
											2009-05-31 04:32:45 +00:00
										 |  |  |     dprintf(s, "id=%d len=%d\n", id, len); | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |     if (len > buf_size || len < 12) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         goto redo; | 
					
						
							|  |  |  |     /* get the data */ | 
					
						
							| 
									
										
										
										
											2009-06-04 06:25:53 +00:00
										 |  |  |     ret = url_read_complete(rt->rtsp_hd, buf, len); | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  |     if (ret != len) | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2008-10-01 12:37:07 +00:00
										 |  |  |     if (rt->transport == RTSP_TRANSPORT_RDT && | 
					
						
							| 
									
										
										
										
											2008-11-15 20:41:59 +00:00
										 |  |  |         ff_rdt_parse_header(buf, len, &id, NULL, NULL, NULL, NULL) < 0) | 
					
						
							| 
									
										
										
										
											2008-10-01 12:37:07 +00:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     /* find the matching stream */ | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |         rtsp_st = rt->rtsp_streams[i]; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |         if (id >= rtsp_st->interleaved_min && | 
					
						
							|  |  |  |             id <= rtsp_st->interleaved_max) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |             goto found; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     goto redo; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | found: | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |     *prtsp_st = rtsp_st; | 
					
						
							|  |  |  |     return len; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  | static int rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  |     int ret, len; | 
					
						
							|  |  |  |     uint8_t buf[10 * RTP_MAX_PACKET_LENGTH]; | 
					
						
							|  |  |  |     RTSPStream *rtsp_st; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-29 10:25:16 +00:00
										 |  |  |     if (rt->nb_byes == rt->nb_rtsp_streams) | 
					
						
							|  |  |  |         return AVERROR_EOF; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |     /* get next frames from the same RTP packet */ | 
					
						
							|  |  |  |     if (rt->cur_transport_priv) { | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         if (rt->transport == RTSP_TRANSPORT_RDT) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |             ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         } else | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |             ret = rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); | 
					
						
							|  |  |  |         if (ret == 0) { | 
					
						
							|  |  |  |             rt->cur_transport_priv = NULL; | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } else if (ret == 1) { | 
					
						
							|  |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         } else | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |             rt->cur_transport_priv = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* read next RTP packet */ | 
					
						
							|  |  |  |  redo: | 
					
						
							|  |  |  |     switch(rt->lower_transport) { | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  | #if CONFIG_RTSP_DEMUXER
 | 
					
						
							|  |  |  |     case RTSP_LOWER_TRANSPORT_TCP: | 
					
						
							|  |  |  |         len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf)); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     case RTSP_LOWER_TRANSPORT_UDP: | 
					
						
							|  |  |  |     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: | 
					
						
							|  |  |  |         len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf)); | 
					
						
							|  |  |  |         if (len >=0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) | 
					
						
							|  |  |  |             rtp_check_and_send_back_rr(rtsp_st->transport_priv, len); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (len < 0) | 
					
						
							|  |  |  |         return len; | 
					
						
							|  |  |  |     if (len == 0) | 
					
						
							|  |  |  |         return AVERROR_EOF; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     if (rt->transport == RTSP_TRANSPORT_RDT) { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |         ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, buf, len); | 
					
						
							| 
									
										
										
										
											2010-04-20 07:34:28 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |         ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, buf, len); | 
					
						
							| 
									
										
										
										
											2010-04-20 07:34:28 +00:00
										 |  |  |         if (ret < 0) { | 
					
						
							|  |  |  |             /* Either bad packet, or a RTCP packet. Check if the
 | 
					
						
							|  |  |  |              * first_rtcp_ntp_time field was initialized. */ | 
					
						
							|  |  |  |             RTPDemuxContext *rtpctx = rtsp_st->transport_priv; | 
					
						
							|  |  |  |             if (rtpctx->first_rtcp_ntp_time != AV_NOPTS_VALUE) { | 
					
						
							|  |  |  |                 /* first_rtcp_ntp_time has been initialized for this stream,
 | 
					
						
							|  |  |  |                  * copy the same value to all other uninitialized streams, | 
					
						
							|  |  |  |                  * in order to map their timestamp origin to the same ntp time | 
					
						
							|  |  |  |                  * as this one. */ | 
					
						
							|  |  |  |                 int i; | 
					
						
							|  |  |  |                 for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2010-09-03 07:10:21 +00:00
										 |  |  |                     RTPDemuxContext *rtpctx2 = rt->rtsp_streams[i]->transport_priv; | 
					
						
							| 
									
										
										
										
											2010-04-20 07:34:28 +00:00
										 |  |  |                     if (rtpctx2 && | 
					
						
							|  |  |  |                         rtpctx2->first_rtcp_ntp_time == AV_NOPTS_VALUE) | 
					
						
							|  |  |  |                         rtpctx2->first_rtcp_ntp_time = rtpctx->first_rtcp_ntp_time; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-08-29 10:25:16 +00:00
										 |  |  |             if (ret == -RTCP_BYE) { | 
					
						
							|  |  |  |                 rt->nb_byes++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 av_log(s, AV_LOG_DEBUG, "Received BYE for stream %d (%d/%d)\n", | 
					
						
							|  |  |  |                        rtsp_st->stream_index, rt->nb_byes, rt->nb_rtsp_streams); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (rt->nb_byes == rt->nb_rtsp_streams) | 
					
						
							|  |  |  |                     return AVERROR_EOF; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-04-20 07:34:28 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |     if (ret < 0) | 
					
						
							|  |  |  |         goto redo; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     if (ret == 1) | 
					
						
							| 
									
										
										
										
											2010-01-04 19:55:43 +00:00
										 |  |  |         /* more packets may follow, so we save the RTP context */ | 
					
						
							|  |  |  |         rt->cur_transport_priv = rtsp_st->transport_priv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2009-11-12 15:34:17 +00:00
										 |  |  |     int ret; | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |     RTSPMessageHeader reply1, *reply = &reply1; | 
					
						
							|  |  |  |     char cmd[1024]; | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |     if (rt->server_type == RTSP_SERVER_REAL) { | 
					
						
							| 
									
										
										
										
											2008-09-07 01:22:18 +00:00
										 |  |  |         int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |         for (i = 0; i < s->nb_streams; i++) | 
					
						
							| 
									
										
										
										
											2010-08-09 23:00:13 +00:00
										 |  |  |             rt->real_setup[i] = s->streams[i]->discard; | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!rt->need_subscription) { | 
					
						
							| 
									
										
										
										
											2010-08-09 23:00:13 +00:00
										 |  |  |             if (memcmp (rt->real_setup, rt->real_setup_cache, | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |                         sizeof(enum AVDiscard) * s->nb_streams)) { | 
					
						
							| 
									
										
										
										
											2010-01-21 19:48:30 +00:00
										 |  |  |                 snprintf(cmd, sizeof(cmd), | 
					
						
							| 
									
										
										
										
											2010-01-21 19:50:40 +00:00
										 |  |  |                          "Unsubscribe: %s\r\n", | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |                          rt->last_subscription); | 
					
						
							|  |  |  |                 ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri, | 
					
						
							|  |  |  |                                  cmd, reply, NULL); | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |                 if (reply->status_code != RTSP_STATUS_OK) | 
					
						
							|  |  |  |                     return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |                 rt->need_subscription = 1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-09-07 01:22:18 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |         if (rt->need_subscription) { | 
					
						
							|  |  |  |             int r, rule_nr, first = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-09 23:00:13 +00:00
										 |  |  |             memcpy(rt->real_setup_cache, rt->real_setup, | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |                    sizeof(enum AVDiscard) * s->nb_streams); | 
					
						
							|  |  |  |             rt->last_subscription[0] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             snprintf(cmd, sizeof(cmd), | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |                      "Subscribe: "); | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |             for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							|  |  |  |                 rule_nr = 0; | 
					
						
							|  |  |  |                 for (r = 0; r < s->nb_streams; r++) { | 
					
						
							|  |  |  |                     if (s->streams[r]->priv_data == rt->rtsp_streams[i]) { | 
					
						
							|  |  |  |                         if (s->streams[r]->discard != AVDISCARD_ALL) { | 
					
						
							|  |  |  |                             if (!first) | 
					
						
							|  |  |  |                                 av_strlcat(rt->last_subscription, ",", | 
					
						
							|  |  |  |                                            sizeof(rt->last_subscription)); | 
					
						
							|  |  |  |                             ff_rdt_subscribe_rule( | 
					
						
							|  |  |  |                                 rt->last_subscription, | 
					
						
							|  |  |  |                                 sizeof(rt->last_subscription), i, rule_nr); | 
					
						
							|  |  |  |                             first = 0; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         rule_nr++; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription); | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |             ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri, | 
					
						
							|  |  |  |                              cmd, reply, NULL); | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |             if (reply->status_code != RTSP_STATUS_OK) | 
					
						
							|  |  |  |                 return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |             rt->need_subscription = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-19 16:26:21 +00:00
										 |  |  |             if (rt->state == RTSP_STATE_STREAMING) | 
					
						
							| 
									
										
										
										
											2009-01-07 14:48:17 +00:00
										 |  |  |                 rtsp_read_play (s); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-09-07 01:22:18 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-30 16:19:28 +00:00
										 |  |  |     ret = rtsp_fetch_packet(s, pkt); | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     if (ret < 0) | 
					
						
							| 
									
										
										
										
											2009-11-12 15:34:17 +00:00
										 |  |  |         return ret; | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* send dummy request to keep TCP connection alive */ | 
					
						
							| 
									
										
										
										
											2010-08-12 13:39:38 +00:00
										 |  |  |     if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) { | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |         if (rt->server_type == RTSP_SERVER_WMS) { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |             ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL); | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |             ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL); | 
					
						
							| 
									
										
										
										
											2009-04-15 13:04:34 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  | /* pause the stream */ | 
					
						
							|  |  |  | static int rtsp_read_pause(AVFormatContext *s) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2009-02-21 22:26:44 +00:00
										 |  |  |     RTSPMessageHeader reply1, *reply = &reply1; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-19 16:26:21 +00:00
										 |  |  |     if (rt->state != RTSP_STATE_STREAMING) | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2008-09-14 13:55:21 +00:00
										 |  |  |     else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) { | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |         ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL); | 
					
						
							| 
									
										
										
										
											2008-09-07 01:24:01 +00:00
										 |  |  |         if (reply->status_code != RTSP_STATUS_OK) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-09-07 01:22:18 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-09-01 13:51:24 +00:00
										 |  |  |     rt->state = RTSP_STATE_PAUSED; | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:27:47 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | static int rtsp_read_seek(AVFormatContext *s, int stream_index, | 
					
						
							| 
									
										
										
										
											2004-10-11 23:53:53 +00:00
										 |  |  |                           int64_t timestamp, int flags) | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     rt->seek_timestamp = av_rescale_q(timestamp, | 
					
						
							|  |  |  |                                       s->streams[stream_index]->time_base, | 
					
						
							|  |  |  |                                       AV_TIME_BASE_Q); | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |     switch(rt->state) { | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     case RTSP_STATE_IDLE: | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2010-02-19 16:26:21 +00:00
										 |  |  |     case RTSP_STATE_STREAMING: | 
					
						
							| 
									
										
										
										
											2009-06-10 15:08:02 +00:00
										 |  |  |         if (rtsp_read_pause(s) != 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         rt->state = RTSP_STATE_SEEKING; | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |         if (rtsp_read_play(s) != 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case RTSP_STATE_PAUSED: | 
					
						
							|  |  |  |         rt->state = RTSP_STATE_IDLE; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | static int rtsp_read_close(AVFormatContext *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     /* NOTE: it is valid to flush the buffer here */ | 
					
						
							| 
									
										
										
										
											2008-09-30 13:18:41 +00:00
										 |  |  |     if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |         url_fclose(&rt->rtsp_gb); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2003-07-15 16:57:35 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-03-25 21:46:14 +00:00
										 |  |  |     ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |     ff_rtsp_close_streams(s); | 
					
						
							| 
									
										
										
										
											2010-06-05 19:41:43 +00:00
										 |  |  |     ff_rtsp_close_connections(s); | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |     ff_network_close(); | 
					
						
							| 
									
										
										
										
											2010-08-09 23:00:13 +00:00
										 |  |  |     rt->real_setup = NULL; | 
					
						
							|  |  |  |     av_freep(&rt->real_setup_cache); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-09 23:40:53 +00:00
										 |  |  | AVInputFormat rtsp_demuxer = { | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     "rtsp", | 
					
						
							| 
									
										
										
										
											2008-06-03 16:20:54 +00:00
										 |  |  |     NULL_IF_CONFIG_SMALL("RTSP input format"), | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  |     sizeof(RTSPState), | 
					
						
							|  |  |  |     rtsp_probe, | 
					
						
							|  |  |  |     rtsp_read_header, | 
					
						
							|  |  |  |     rtsp_read_packet, | 
					
						
							|  |  |  |     rtsp_read_close, | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |     rtsp_read_seek, | 
					
						
							| 
									
										
										
										
											2002-10-06 23:06:06 +00:00
										 |  |  |     .flags = AVFMT_NOFILE, | 
					
						
							| 
									
										
										
										
											2003-11-10 18:39:26 +00:00
										 |  |  |     .read_play = rtsp_read_play, | 
					
						
							|  |  |  |     .read_pause = rtsp_read_pause, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2007-04-26 23:41:20 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-20 14:54:13 +00:00
										 |  |  | static int sdp_probe(AVProbeData *p1) | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-03-16 19:06:34 +00:00
										 |  |  |     const char *p = p1->buf, *p_end = p1->buf + p1->buf_size; | 
					
						
							| 
									
										
										
										
											2002-11-20 14:54:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |     /* we look for a line beginning "c=IN IP" */ | 
					
						
							| 
									
										
										
										
											2005-03-16 19:06:34 +00:00
										 |  |  |     while (p < p_end && *p != '\0') { | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |         if (p + sizeof("c=IN IP") - 1 < p_end && | 
					
						
							|  |  |  |             av_strstart(p, "c=IN IP", NULL)) | 
					
						
							| 
									
										
										
										
											2002-11-20 14:54:13 +00:00
										 |  |  |             return AVPROBE_SCORE_MAX / 2; | 
					
						
							| 
									
										
										
										
											2005-03-16 19:06:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |         while (p < p_end - 1 && *p != '\n') p++; | 
					
						
							| 
									
										
										
										
											2005-03-16 19:06:34 +00:00
										 |  |  |         if (++p >= p_end) | 
					
						
							| 
									
										
										
										
											2002-11-20 14:54:13 +00:00
										 |  |  |             break; | 
					
						
							|  |  |  |         if (*p == '\r') | 
					
						
							|  |  |  |             p++; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | static int sdp_read_header(AVFormatContext *s, AVFormatParameters *ap) | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |     RTSPState *rt = s->priv_data; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     RTSPStream *rtsp_st; | 
					
						
							|  |  |  |     int size, i, err; | 
					
						
							|  |  |  |     char *content; | 
					
						
							|  |  |  |     char url[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |     if (!ff_network_init()) | 
					
						
							|  |  |  |         return AVERROR(EIO); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     /* read the whole sdp file */ | 
					
						
							|  |  |  |     /* XXX: better loading */ | 
					
						
							|  |  |  |     content = av_malloc(SDP_MAX_SIZE); | 
					
						
							| 
									
										
										
										
											2007-11-21 07:41:00 +00:00
										 |  |  |     size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1); | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     if (size <= 0) { | 
					
						
							|  |  |  |         av_free(content); | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     content[size] ='\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sdp_parse(s, content); | 
					
						
							|  |  |  |     av_free(content); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* open each RTP stream */ | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  |     for (i = 0; i < rt->nb_rtsp_streams; i++) { | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |         char namebuf[50]; | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |         rtsp_st = rt->rtsp_streams[i]; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |         getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip), | 
					
						
							|  |  |  |                     namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |         ff_url_join(url, sizeof(url), "rtp", NULL, | 
					
						
							| 
									
										
										
										
											2010-08-25 15:32:00 +00:00
										 |  |  |                     namebuf, rtsp_st->sdp_port, | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |                     "?localport=%d&ttl=%d", rtsp_st->sdp_port, | 
					
						
							|  |  |  |                     rtsp_st->sdp_ttl); | 
					
						
							| 
									
										
										
										
											2006-10-27 18:19:29 +00:00
										 |  |  |         if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |             err = AVERROR_INVALIDDATA; | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-09-11 17:43:04 +00:00
										 |  |  |         if ((err = rtsp_open_transport_ctx(s, rtsp_st))) | 
					
						
							| 
									
										
										
										
											2003-10-29 14:25:27 +00:00
										 |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2010-01-07 22:41:14 +00:00
										 |  |  | fail: | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |     ff_rtsp_close_streams(s); | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |     ff_network_close(); | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sdp_read_close(AVFormatContext *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-02-23 00:35:50 +00:00
										 |  |  |     ff_rtsp_close_streams(s); | 
					
						
							| 
									
										
										
										
											2010-03-05 22:35:21 +00:00
										 |  |  |     ff_network_close(); | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-10 21:14:37 +00:00
										 |  |  | AVInputFormat sdp_demuxer = { | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     "sdp", | 
					
						
							| 
									
										
										
										
											2008-06-03 16:20:54 +00:00
										 |  |  |     NULL_IF_CONFIG_SMALL("SDP"), | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     sizeof(RTSPState), | 
					
						
							|  |  |  |     sdp_probe, | 
					
						
							|  |  |  |     sdp_read_header, | 
					
						
							| 
									
										
										
										
											2009-12-30 16:19:28 +00:00
										 |  |  |     rtsp_fetch_packet, | 
					
						
							| 
									
										
										
										
											2002-11-18 17:24:39 +00:00
										 |  |  |     sdp_read_close, | 
					
						
							|  |  |  | }; |