• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/rtsp.c

Go to the documentation of this file.
00001 /*
00002  * RTSP/SDP client
00003  * Copyright (c) 2002 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 /* needed by inet_aton() */
00023 #define _SVID_SOURCE
00024 
00025 #include "libavutil/avstring.h"
00026 #include "libavutil/intreadwrite.h"
00027 #include "avformat.h"
00028 
00029 #include <sys/time.h>
00030 #if HAVE_SYS_SELECT_H
00031 #include <sys/select.h>
00032 #endif
00033 #include <strings.h>
00034 #include "network.h"
00035 #include "rtsp.h"
00036 
00037 #include "rtpdec.h"
00038 #include "rdt.h"
00039 
00040 //#define DEBUG
00041 //#define DEBUG_RTP_TCP
00042 
00043 static int rtsp_read_play(AVFormatContext *s);
00044 
00045 /* XXX: currently, the only way to change the protocols consists in
00046    changing this variable */
00047 
00048 #if LIBAVFORMAT_VERSION_INT < (53 << 16)
00049 int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP);
00050 #endif
00051 
00052 static int rtsp_probe(AVProbeData *p)
00053 {
00054     if (av_strstart(p->filename, "rtsp:", NULL))
00055         return AVPROBE_SCORE_MAX;
00056     return 0;
00057 }
00058 
00059 static int redir_isspace(int c)
00060 {
00061     return c == ' ' || c == '\t' || c == '\n' || c == '\r';
00062 }
00063 
00064 static void skip_spaces(const char **pp)
00065 {
00066     const char *p;
00067     p = *pp;
00068     while (redir_isspace(*p))
00069         p++;
00070     *pp = p;
00071 }
00072 
00073 static void get_word_sep(char *buf, int buf_size, const char *sep,
00074                          const char **pp)
00075 {
00076     const char *p;
00077     char *q;
00078 
00079     p = *pp;
00080     if (*p == '/')
00081         p++;
00082     skip_spaces(&p);
00083     q = buf;
00084     while (!strchr(sep, *p) && *p != '\0') {
00085         if ((q - buf) < buf_size - 1)
00086             *q++ = *p;
00087         p++;
00088     }
00089     if (buf_size > 0)
00090         *q = '\0';
00091     *pp = p;
00092 }
00093 
00094 static void get_word(char *buf, int buf_size, const char **pp)
00095 {
00096     const char *p;
00097     char *q;
00098 
00099     p = *pp;
00100     skip_spaces(&p);
00101     q = buf;
00102     while (!redir_isspace(*p) && *p != '\0') {
00103         if ((q - buf) < buf_size - 1)
00104             *q++ = *p;
00105         p++;
00106     }
00107     if (buf_size > 0)
00108         *q = '\0';
00109     *pp = p;
00110 }
00111 
00112 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
00113    params>] */
00114 static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payload_type, const char *p)
00115 {
00116     char buf[256];
00117     int i;
00118     AVCodec *c;
00119     const char *c_name;
00120 
00121     /* Loop into AVRtpDynamicPayloadTypes[] and AVRtpPayloadTypes[] and
00122        see if we can handle this kind of payload */
00123     get_word_sep(buf, sizeof(buf), "/", &p);
00124     if (payload_type >= RTP_PT_PRIVATE) {
00125         RTPDynamicProtocolHandler *handler= RTPFirstDynamicPayloadHandler;
00126         while(handler) {
00127             if (!strcmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) {
00128                 codec->codec_id = handler->codec_id;
00129                 rtsp_st->dynamic_handler= handler;
00130                 if(handler->open) {
00131                     rtsp_st->dynamic_protocol_context= handler->open();
00132                 }
00133                 break;
00134             }
00135             handler= handler->next;
00136         }
00137     } else {
00138         /* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */
00139         /* search into AVRtpPayloadTypes[] */
00140         codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type);
00141     }
00142 
00143     c = avcodec_find_decoder(codec->codec_id);
00144     if (c && c->name)
00145         c_name = c->name;
00146     else
00147         c_name = (char *)NULL;
00148 
00149     if (c_name) {
00150         get_word_sep(buf, sizeof(buf), "/", &p);
00151         i = atoi(buf);
00152         switch (codec->codec_type) {
00153             case CODEC_TYPE_AUDIO:
00154                 av_log(codec, AV_LOG_DEBUG, " audio codec set to : %s\n", c_name);
00155                 codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE;
00156                 codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS;
00157                 if (i > 0) {
00158                     codec->sample_rate = i;
00159                     get_word_sep(buf, sizeof(buf), "/", &p);
00160                     i = atoi(buf);
00161                     if (i > 0)
00162                         codec->channels = i;
00163                     // TODO: there is a bug here; if it is a mono stream, and less than 22000Hz, faad upconverts to stereo and twice the
00164                     //  frequency.  No problem, but the sample rate is being set here by the sdp line.  Upcoming patch forthcoming. (rdm)
00165                 }
00166                 av_log(codec, AV_LOG_DEBUG, " audio samplerate set to : %i\n", codec->sample_rate);
00167                 av_log(codec, AV_LOG_DEBUG, " audio channels set to : %i\n", codec->channels);
00168                 break;
00169             case CODEC_TYPE_VIDEO:
00170                 av_log(codec, AV_LOG_DEBUG, " video codec set to : %s\n", c_name);
00171                 break;
00172             default:
00173                 break;
00174         }
00175         return 0;
00176     }
00177 
00178     return -1;
00179 }
00180 
00181 /* return the length and optionnaly the data */
00182 static int hex_to_data(uint8_t *data, const char *p)
00183 {
00184     int c, len, v;
00185 
00186     len = 0;
00187     v = 1;
00188     for(;;) {
00189         skip_spaces(&p);
00190         if (p == '\0')
00191             break;
00192         c = toupper((unsigned char)*p++);
00193         if (c >= '0' && c <= '9')
00194             c = c - '0';
00195         else if (c >= 'A' && c <= 'F')
00196             c = c - 'A' + 10;
00197         else
00198             break;
00199         v = (v << 4) | c;
00200         if (v & 0x100) {
00201             if (data)
00202                 data[len] = v;
00203             len++;
00204             v = 1;
00205         }
00206     }
00207     return len;
00208 }
00209 
00210 static void sdp_parse_fmtp_config(AVCodecContext *codec, char *attr, char *value)
00211 {
00212     switch (codec->codec_id) {
00213         case CODEC_ID_MPEG4:
00214         case CODEC_ID_AAC:
00215             if (!strcmp(attr, "config")) {
00216                 /* decode the hexa encoded parameter */
00217                 int len = hex_to_data(NULL, value);
00218                 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
00219                 if (!codec->extradata)
00220                     return;
00221                 codec->extradata_size = len;
00222                 hex_to_data(codec->extradata, value);
00223             }
00224             break;
00225         default:
00226             break;
00227     }
00228     return;
00229 }
00230 
00231 typedef struct {
00232     const char *str;
00233     uint16_t type;
00234     uint32_t offset;
00235 } AttrNameMap;
00236 
00237 /* All known fmtp parmeters and the corresping RTPAttrTypeEnum */
00238 #define ATTR_NAME_TYPE_INT 0
00239 #define ATTR_NAME_TYPE_STR 1
00240 static const AttrNameMap attr_names[]=
00241 {
00242     {"SizeLength",       ATTR_NAME_TYPE_INT, offsetof(RTPPayloadData, sizelength)},
00243     {"IndexLength",      ATTR_NAME_TYPE_INT, offsetof(RTPPayloadData, indexlength)},
00244     {"IndexDeltaLength", ATTR_NAME_TYPE_INT, offsetof(RTPPayloadData, indexdeltalength)},
00245     {"profile-level-id", ATTR_NAME_TYPE_INT, offsetof(RTPPayloadData, profile_level_id)},
00246     {"StreamType",       ATTR_NAME_TYPE_INT, offsetof(RTPPayloadData, streamtype)},
00247     {"mode",             ATTR_NAME_TYPE_STR, offsetof(RTPPayloadData, mode)},
00248     {NULL, -1, -1},
00249 };
00250 
00254 int rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, char *value, int value_size)
00255 {
00256     skip_spaces(p);
00257     if(**p)
00258     {
00259         get_word_sep(attr, attr_size, "=", p);
00260         if (**p == '=')
00261             (*p)++;
00262         get_word_sep(value, value_size, ";", p);
00263         if (**p == ';')
00264             (*p)++;
00265         return 1;
00266     }
00267     return 0;
00268 }
00269 
00270 /* parse a SDP line and save stream attributes */
00271 static void sdp_parse_fmtp(AVStream *st, const char *p)
00272 {
00273     char attr[256];
00274     char value[4096];
00275     int i;
00276 
00277     RTSPStream *rtsp_st = st->priv_data;
00278     AVCodecContext *codec = st->codec;
00279     RTPPayloadData *rtp_payload_data = &rtsp_st->rtp_payload_data;
00280 
00281     /* loop on each attribute */
00282     while(rtsp_next_attr_and_value(&p, attr, sizeof(attr), value, sizeof(value)))
00283     {
00284         /* grab the codec extra_data from the config parameter of the fmtp line */
00285         sdp_parse_fmtp_config(codec, attr, value);
00286         /* Looking for a known attribute */
00287         for (i = 0; attr_names[i].str; ++i) {
00288             if (!strcasecmp(attr, attr_names[i].str)) {
00289                 if (attr_names[i].type == ATTR_NAME_TYPE_INT)
00290                     *(int *)((char *)rtp_payload_data + attr_names[i].offset) = atoi(value);
00291                 else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
00292                     *(char **)((char *)rtp_payload_data + attr_names[i].offset) = av_strdup(value);
00293             }
00294         }
00295     }
00296 }
00297 
00302 static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end)
00303 {
00304     char buf[256];
00305 
00306     skip_spaces(&p);
00307     if (!av_stristart(p, "npt=", &p))
00308         return;
00309 
00310     *start = AV_NOPTS_VALUE;
00311     *end = AV_NOPTS_VALUE;
00312 
00313     get_word_sep(buf, sizeof(buf), "-", &p);
00314     *start = parse_date(buf, 1);
00315     if (*p == '-') {
00316         p++;
00317         get_word_sep(buf, sizeof(buf), "-", &p);
00318         *end = parse_date(buf, 1);
00319     }
00320 //    av_log(NULL, AV_LOG_DEBUG, "Range Start: %lld\n", *start);
00321 //    av_log(NULL, AV_LOG_DEBUG, "Range End: %lld\n", *end);
00322 }
00323 
00324 typedef struct SDPParseState {
00325     /* SDP only */
00326     struct in_addr default_ip;
00327     int default_ttl;
00328     int skip_media; 
00329 } SDPParseState;
00330 
00331 static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
00332                            int letter, const char *buf)
00333 {
00334     RTSPState *rt = s->priv_data;
00335     char buf1[64], st_type[64];
00336     const char *p;
00337     enum CodecType codec_type;
00338     int payload_type, i;
00339     AVStream *st;
00340     RTSPStream *rtsp_st;
00341     struct in_addr sdp_ip;
00342     int ttl;
00343 
00344 #ifdef DEBUG
00345     printf("sdp: %c='%s'\n", letter, buf);
00346 #endif
00347 
00348     p = buf;
00349     if (s1->skip_media && letter != 'm')
00350         return;
00351     switch(letter) {
00352     case 'c':
00353         get_word(buf1, sizeof(buf1), &p);
00354         if (strcmp(buf1, "IN") != 0)
00355             return;
00356         get_word(buf1, sizeof(buf1), &p);
00357         if (strcmp(buf1, "IP4") != 0)
00358             return;
00359         get_word_sep(buf1, sizeof(buf1), "/", &p);
00360         if (inet_aton(buf1, &sdp_ip) == 0)
00361             return;
00362         ttl = 16;
00363         if (*p == '/') {
00364             p++;
00365             get_word_sep(buf1, sizeof(buf1), "/", &p);
00366             ttl = atoi(buf1);
00367         }
00368         if (s->nb_streams == 0) {
00369             s1->default_ip = sdp_ip;
00370             s1->default_ttl = ttl;
00371         } else {
00372             st = s->streams[s->nb_streams - 1];
00373             rtsp_st = st->priv_data;
00374             rtsp_st->sdp_ip = sdp_ip;
00375             rtsp_st->sdp_ttl = ttl;
00376         }
00377         break;
00378     case 's':
00379         av_metadata_set(&s->metadata, "title", p);
00380         break;
00381     case 'i':
00382         if (s->nb_streams == 0) {
00383             av_metadata_set(&s->metadata, "comment", p);
00384             break;
00385         }
00386         break;
00387     case 'm':
00388         /* new stream */
00389         s1->skip_media = 0;
00390         get_word(st_type, sizeof(st_type), &p);
00391         if (!strcmp(st_type, "audio")) {
00392             codec_type = CODEC_TYPE_AUDIO;
00393         } else if (!strcmp(st_type, "video")) {
00394             codec_type = CODEC_TYPE_VIDEO;
00395         } else {
00396             s1->skip_media = 1;
00397             return;
00398         }
00399         rtsp_st = av_mallocz(sizeof(RTSPStream));
00400         if (!rtsp_st)
00401             return;
00402         rtsp_st->stream_index = -1;
00403         dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st);
00404 
00405         rtsp_st->sdp_ip = s1->default_ip;
00406         rtsp_st->sdp_ttl = s1->default_ttl;
00407 
00408         get_word(buf1, sizeof(buf1), &p); /* port */
00409         rtsp_st->sdp_port = atoi(buf1);
00410 
00411         get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */
00412 
00413         /* XXX: handle list of formats */
00414         get_word(buf1, sizeof(buf1), &p); /* format list */
00415         rtsp_st->sdp_payload_type = atoi(buf1);
00416 
00417         if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) {
00418             /* no corresponding stream */
00419         } else {
00420             st = av_new_stream(s, 0);
00421             if (!st)
00422                 return;
00423             st->priv_data = rtsp_st;
00424             rtsp_st->stream_index = st->index;
00425             st->codec->codec_type = codec_type;
00426             if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
00427                 /* if standard payload type, we can find the codec right now */
00428                 ff_rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
00429             }
00430         }
00431         /* put a default control url */
00432         av_strlcpy(rtsp_st->control_url, s->filename, sizeof(rtsp_st->control_url));
00433         break;
00434     case 'a':
00435         if (av_strstart(p, "control:", &p) && s->nb_streams > 0) {
00436             char proto[32];
00437             /* get the control url */
00438             st = s->streams[s->nb_streams - 1];
00439             rtsp_st = st->priv_data;
00440 
00441             /* XXX: may need to add full url resolution */
00442             url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p);
00443             if (proto[0] == '\0') {
00444                 /* relative control URL */
00445                 av_strlcat(rtsp_st->control_url, "/", sizeof(rtsp_st->control_url));
00446                 av_strlcat(rtsp_st->control_url, p,   sizeof(rtsp_st->control_url));
00447             } else {
00448                 av_strlcpy(rtsp_st->control_url, p,   sizeof(rtsp_st->control_url));
00449             }
00450         } else if (av_strstart(p, "rtpmap:", &p) && s->nb_streams > 0) {
00451             /* NOTE: rtpmap is only supported AFTER the 'm=' tag */
00452             get_word(buf1, sizeof(buf1), &p);
00453             payload_type = atoi(buf1);
00454             st = s->streams[s->nb_streams - 1];
00455             rtsp_st = st->priv_data;
00456             sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p);
00457         } else if (av_strstart(p, "fmtp:", &p)) {
00458             /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */
00459             get_word(buf1, sizeof(buf1), &p);
00460             payload_type = atoi(buf1);
00461             for(i = 0; i < s->nb_streams;i++) {
00462                 st = s->streams[i];
00463                 rtsp_st = st->priv_data;
00464                 if (rtsp_st->sdp_payload_type == payload_type) {
00465                     if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
00466                         if(!rtsp_st->dynamic_handler->parse_sdp_a_line(s, i, rtsp_st->dynamic_protocol_context, buf)) {
00467                             sdp_parse_fmtp(st, p);
00468                         }
00469                     } else {
00470                         sdp_parse_fmtp(st, p);
00471                     }
00472                 }
00473             }
00474         } else if(av_strstart(p, "framesize:", &p)) {
00475             // let dynamic protocol handlers have a stab at the line.
00476             get_word(buf1, sizeof(buf1), &p);
00477             payload_type = atoi(buf1);
00478             for(i = 0; i < s->nb_streams;i++) {
00479                 st = s->streams[i];
00480                 rtsp_st = st->priv_data;
00481                 if (rtsp_st->sdp_payload_type == payload_type) {
00482                     if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
00483                         rtsp_st->dynamic_handler->parse_sdp_a_line(s, i, rtsp_st->dynamic_protocol_context, buf);
00484                     }
00485                 }
00486             }
00487         } else if(av_strstart(p, "range:", &p)) {
00488             int64_t start, end;
00489 
00490             // this is so that seeking on a streamed file can work.
00491             rtsp_parse_range_npt(p, &start, &end);
00492             s->start_time= start;
00493             s->duration= (end==AV_NOPTS_VALUE)?AV_NOPTS_VALUE:end-start; // AV_NOPTS_VALUE means live broadcast (and can't seek)
00494         } else if (av_strstart(p, "IsRealDataType:integer;",&p)) {
00495             if (atoi(p) == 1)
00496                 rt->transport = RTSP_TRANSPORT_RDT;
00497         } else if (s->nb_streams > 0) {
00498             if (rt->server_type == RTSP_SERVER_REAL)
00499                 ff_real_parse_sdp_a_line(s, s->nb_streams - 1, p);
00500 
00501             rtsp_st = s->streams[s->nb_streams - 1]->priv_data;
00502             if (rtsp_st->dynamic_handler &&
00503                 rtsp_st->dynamic_handler->parse_sdp_a_line)
00504                 rtsp_st->dynamic_handler->parse_sdp_a_line(s, s->nb_streams - 1,
00505                     rtsp_st->dynamic_protocol_context, buf);
00506         }
00507         break;
00508     }
00509 }
00510 
00511 static int sdp_parse(AVFormatContext *s, const char *content)
00512 {
00513     const char *p;
00514     int letter;
00515     /* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
00516      * contain long SDP lines containing complete ASF Headers (several
00517      * kB) or arrays of MDPR (RM stream descriptor) headers plus
00518      * "rulebooks" describing their properties. Therefore, the SDP line
00519      * buffer is large. */
00520     char buf[8192], *q;
00521     SDPParseState sdp_parse_state, *s1 = &sdp_parse_state;
00522 
00523     memset(s1, 0, sizeof(SDPParseState));
00524     p = content;
00525     for(;;) {
00526         skip_spaces(&p);
00527         letter = *p;
00528         if (letter == '\0')
00529             break;
00530         p++;
00531         if (*p != '=')
00532             goto next_line;
00533         p++;
00534         /* get the content */
00535         q = buf;
00536         while (*p != '\n' && *p != '\r' && *p != '\0') {
00537             if ((q - buf) < sizeof(buf) - 1)
00538                 *q++ = *p;
00539             p++;
00540         }
00541         *q = '\0';
00542         sdp_parse_line(s, s1, letter, buf);
00543     next_line:
00544         while (*p != '\n' && *p != '\0')
00545             p++;
00546         if (*p == '\n')
00547             p++;
00548     }
00549     return 0;
00550 }
00551 
00552 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
00553 {
00554     const char *p;
00555     int v;
00556 
00557     p = *pp;
00558     skip_spaces(&p);
00559     v = strtol(p, (char **)&p, 10);
00560     if (*p == '-') {
00561         p++;
00562         *min_ptr = v;
00563         v = strtol(p, (char **)&p, 10);
00564         *max_ptr = v;
00565     } else {
00566         *min_ptr = v;
00567         *max_ptr = v;
00568     }
00569     *pp = p;
00570 }
00571 
00572 /* XXX: only one transport specification is parsed */
00573 static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p)
00574 {
00575     char transport_protocol[16];
00576     char profile[16];
00577     char lower_transport[16];
00578     char parameter[16];
00579     RTSPTransportField *th;
00580     char buf[256];
00581 
00582     reply->nb_transports = 0;
00583 
00584     for(;;) {
00585         skip_spaces(&p);
00586         if (*p == '\0')
00587             break;
00588 
00589         th = &reply->transports[reply->nb_transports];
00590 
00591         get_word_sep(transport_protocol, sizeof(transport_protocol),
00592                      "/", &p);
00593         if (*p == '/')
00594             p++;
00595         if (!strcasecmp (transport_protocol, "rtp")) {
00596             get_word_sep(profile, sizeof(profile), "/;,", &p);
00597             lower_transport[0] = '\0';
00598             /* rtp/avp/<protocol> */
00599             if (*p == '/') {
00600                 p++;
00601                 get_word_sep(lower_transport, sizeof(lower_transport),
00602                              ";,", &p);
00603             }
00604             th->transport = RTSP_TRANSPORT_RTP;
00605         } else if (!strcasecmp (transport_protocol, "x-pn-tng") ||
00606                    !strcasecmp (transport_protocol, "x-real-rdt")) {
00607             /* x-pn-tng/<protocol> */
00608             get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p);
00609             profile[0] = '\0';
00610             th->transport = RTSP_TRANSPORT_RDT;
00611         }
00612         if (!strcasecmp(lower_transport, "TCP"))
00613             th->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
00614         else
00615             th->lower_transport = RTSP_LOWER_TRANSPORT_UDP;
00616 
00617         if (*p == ';')
00618             p++;
00619         /* get each parameter */
00620         while (*p != '\0' && *p != ',') {
00621             get_word_sep(parameter, sizeof(parameter), "=;,", &p);
00622             if (!strcmp(parameter, "port")) {
00623                 if (*p == '=') {
00624                     p++;
00625                     rtsp_parse_range(&th->port_min, &th->port_max, &p);
00626                 }
00627             } else if (!strcmp(parameter, "client_port")) {
00628                 if (*p == '=') {
00629                     p++;
00630                     rtsp_parse_range(&th->client_port_min,
00631                                      &th->client_port_max, &p);
00632                 }
00633             } else if (!strcmp(parameter, "server_port")) {
00634                 if (*p == '=') {
00635                     p++;
00636                     rtsp_parse_range(&th->server_port_min,
00637                                      &th->server_port_max, &p);
00638                 }
00639             } else if (!strcmp(parameter, "interleaved")) {
00640                 if (*p == '=') {
00641                     p++;
00642                     rtsp_parse_range(&th->interleaved_min,
00643                                      &th->interleaved_max, &p);
00644                 }
00645             } else if (!strcmp(parameter, "multicast")) {
00646                 if (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP)
00647                     th->lower_transport = RTSP_LOWER_TRANSPORT_UDP_MULTICAST;
00648             } else if (!strcmp(parameter, "ttl")) {
00649                 if (*p == '=') {
00650                     p++;
00651                     th->ttl = strtol(p, (char **)&p, 10);
00652                 }
00653             } else if (!strcmp(parameter, "destination")) {
00654                 struct in_addr ipaddr;
00655 
00656                 if (*p == '=') {
00657                     p++;
00658                     get_word_sep(buf, sizeof(buf), ";,", &p);
00659                     if (inet_aton(buf, &ipaddr))
00660                         th->destination = ntohl(ipaddr.s_addr);
00661                 }
00662             }
00663             while (*p != ';' && *p != '\0' && *p != ',')
00664                 p++;
00665             if (*p == ';')
00666                 p++;
00667         }
00668         if (*p == ',')
00669             p++;
00670 
00671         reply->nb_transports++;
00672     }
00673 }
00674 
00675 void rtsp_parse_line(RTSPMessageHeader *reply, const char *buf)
00676 {
00677     const char *p;
00678 
00679     /* NOTE: we do case independent match for broken servers */
00680     p = buf;
00681     if (av_stristart(p, "Session:", &p)) {
00682         get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
00683     } else if (av_stristart(p, "Content-Length:", &p)) {
00684         reply->content_length = strtol(p, NULL, 10);
00685     } else if (av_stristart(p, "Transport:", &p)) {
00686         rtsp_parse_transport(reply, p);
00687     } else if (av_stristart(p, "CSeq:", &p)) {
00688         reply->seq = strtol(p, NULL, 10);
00689     } else if (av_stristart(p, "Range:", &p)) {
00690         rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end);
00691     } else if (av_stristart(p, "RealChallenge1:", &p)) {
00692         skip_spaces(&p);
00693         av_strlcpy(reply->real_challenge, p, sizeof(reply->real_challenge));
00694     } else if (av_stristart(p, "Server:", &p)) {
00695         skip_spaces(&p);
00696         av_strlcpy(reply->server, p, sizeof(reply->server));
00697     }
00698 }
00699 
00700 static int url_readbuf(URLContext *h, unsigned char *buf, int size)
00701 {
00702     int ret, len;
00703 
00704     len = 0;
00705     while (len < size) {
00706         ret = url_read(h, buf+len, size-len);
00707         if (ret < 1)
00708             return ret;
00709         len += ret;
00710     }
00711     return len;
00712 }
00713 
00714 /* skip a RTP/TCP interleaved packet */
00715 static void rtsp_skip_packet(AVFormatContext *s)
00716 {
00717     RTSPState *rt = s->priv_data;
00718     int ret, len, len1;
00719     uint8_t buf[1024];
00720 
00721     ret = url_readbuf(rt->rtsp_hd, buf, 3);
00722     if (ret != 3)
00723         return;
00724     len = AV_RB16(buf + 1);
00725 #ifdef DEBUG
00726     printf("skipping RTP packet len=%d\n", len);
00727 #endif
00728     /* skip payload */
00729     while (len > 0) {
00730         len1 = len;
00731         if (len1 > sizeof(buf))
00732             len1 = sizeof(buf);
00733         ret = url_readbuf(rt->rtsp_hd, buf, len1);
00734         if (ret != len1)
00735             return;
00736         len -= len1;
00737     }
00738 }
00739 
00740 static void rtsp_send_cmd(AVFormatContext *s,
00741                           const char *cmd, RTSPMessageHeader *reply,
00742                           unsigned char **content_ptr)
00743 {
00744     RTSPState *rt = s->priv_data;
00745     char buf[4096], buf1[1024], *q;
00746     unsigned char ch;
00747     const char *p;
00748     int content_length, line_count;
00749     unsigned char *content = NULL;
00750 
00751     memset(reply, 0, sizeof(*reply));
00752 
00753     rt->seq++;
00754     av_strlcpy(buf, cmd, sizeof(buf));
00755     snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
00756     av_strlcat(buf, buf1, sizeof(buf));
00757     if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
00758         snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
00759         av_strlcat(buf, buf1, sizeof(buf));
00760     }
00761     av_strlcat(buf, "\r\n", sizeof(buf));
00762 #ifdef DEBUG
00763     printf("Sending:\n%s--\n", buf);
00764 #endif
00765     url_write(rt->rtsp_hd, buf, strlen(buf));
00766 
00767     /* parse reply (XXX: use buffers) */
00768     line_count = 0;
00769     rt->last_reply[0] = '\0';
00770     for(;;) {
00771         q = buf;
00772         for(;;) {
00773             if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1)
00774                 break;
00775             if (ch == '\n')
00776                 break;
00777             if (ch == '$') {
00778                 /* XXX: only parse it if first char on line ? */
00779                 rtsp_skip_packet(s);
00780             } else if (ch != '\r') {
00781                 if ((q - buf) < sizeof(buf) - 1)
00782                     *q++ = ch;
00783             }
00784         }
00785         *q = '\0';
00786 #ifdef DEBUG
00787         printf("line='%s'\n", buf);
00788 #endif
00789         /* test if last line */
00790         if (buf[0] == '\0')
00791             break;
00792         p = buf;
00793         if (line_count == 0) {
00794             /* get reply code */
00795             get_word(buf1, sizeof(buf1), &p);
00796             get_word(buf1, sizeof(buf1), &p);
00797             reply->status_code = atoi(buf1);
00798         } else {
00799             rtsp_parse_line(reply, p);
00800             av_strlcat(rt->last_reply, p,    sizeof(rt->last_reply));
00801             av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply));
00802         }
00803         line_count++;
00804     }
00805 
00806     if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
00807         av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
00808 
00809     content_length = reply->content_length;
00810     if (content_length > 0) {
00811         /* leave some room for a trailing '\0' (useful for simple parsing) */
00812         content = av_malloc(content_length + 1);
00813         (void)url_readbuf(rt->rtsp_hd, content, content_length);
00814         content[content_length] = '\0';
00815     }
00816     if (content_ptr)
00817         *content_ptr = content;
00818     else
00819         av_free(content);
00820 }
00821 
00822 
00823 /* close and free RTSP streams */
00824 static void rtsp_close_streams(RTSPState *rt)
00825 {
00826     int i;
00827     RTSPStream *rtsp_st;
00828 
00829     for(i=0;i<rt->nb_rtsp_streams;i++) {
00830         rtsp_st = rt->rtsp_streams[i];
00831         if (rtsp_st) {
00832             if (rtsp_st->transport_priv) {
00833                 if (rt->transport == RTSP_TRANSPORT_RDT)
00834                     ff_rdt_parse_close(rtsp_st->transport_priv);
00835                 else
00836                     rtp_parse_close(rtsp_st->transport_priv);
00837             }
00838             if (rtsp_st->rtp_handle)
00839                 url_close(rtsp_st->rtp_handle);
00840             if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
00841                 rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
00842         }
00843     }
00844     av_free(rt->rtsp_streams);
00845 }
00846 
00847 static int
00848 rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
00849 {
00850     RTSPState *rt = s->priv_data;
00851     AVStream *st = NULL;
00852 
00853     /* open the RTP context */
00854     if (rtsp_st->stream_index >= 0)
00855         st = s->streams[rtsp_st->stream_index];
00856     if (!st)
00857         s->ctx_flags |= AVFMTCTX_NOHEADER;
00858 
00859     if (rt->transport == RTSP_TRANSPORT_RDT)
00860         rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
00861                                             rtsp_st->dynamic_protocol_context,
00862                                             rtsp_st->dynamic_handler);
00863     else
00864         rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle,
00865                                          rtsp_st->sdp_payload_type,
00866                                          &rtsp_st->rtp_payload_data);
00867 
00868     if (!rtsp_st->transport_priv) {
00869          return AVERROR(ENOMEM);
00870     } else if (rt->transport != RTSP_TRANSPORT_RDT) {
00871         if(rtsp_st->dynamic_handler) {
00872             rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
00873                                            rtsp_st->dynamic_protocol_context,
00874                                            rtsp_st->dynamic_handler);
00875         }
00876     }
00877 
00878     return 0;
00879 }
00880 
00884 static int
00885 make_setup_request (AVFormatContext *s, const char *host, int port,
00886                     int lower_transport, const char *real_challenge)
00887 {
00888     RTSPState *rt = s->priv_data;
00889     int j, i, err, interleave = 0;
00890     RTSPStream *rtsp_st;
00891     RTSPMessageHeader reply1, *reply = &reply1;
00892     char cmd[2048];
00893     const char *trans_pref;
00894 
00895     if (rt->transport == RTSP_TRANSPORT_RDT)
00896         trans_pref = "x-pn-tng";
00897     else
00898         trans_pref = "RTP/AVP";
00899 
00900     /* for each stream, make the setup request */
00901     /* XXX: we assume the same server is used for the control of each
00902        RTSP stream */
00903 
00904     for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
00905         char transport[2048];
00906 
00907         rtsp_st = rt->rtsp_streams[i];
00908 
00909         /* RTP/UDP */
00910         if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) {
00911             char buf[256];
00912 
00913             /* first try in specified port range */
00914             if (RTSP_RTP_PORT_MIN != 0) {
00915                 while(j <= RTSP_RTP_PORT_MAX) {
00916                     snprintf(buf, sizeof(buf), "rtp://%s?localport=%d", host, j);
00917                     j += 2; /* we will use two port by rtp stream (rtp and rtcp) */
00918                     if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) {
00919                         goto rtp_opened;
00920                     }
00921                 }
00922             }
00923 
00924 /*            then try on any port
00925 **            if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) {
00926 **                err = AVERROR_INVALIDDATA;
00927 **                goto fail;
00928 **            }
00929 */
00930 
00931         rtp_opened:
00932             port = rtp_get_local_port(rtsp_st->rtp_handle);
00933             snprintf(transport, sizeof(transport) - 1,
00934                      "%s/UDP;", trans_pref);
00935             if (rt->server_type != RTSP_SERVER_REAL)
00936                 av_strlcat(transport, "unicast;", sizeof(transport));
00937             av_strlcatf(transport, sizeof(transport),
00938                      "client_port=%d", port);
00939             if (rt->transport == RTSP_TRANSPORT_RTP)
00940                 av_strlcatf(transport, sizeof(transport), "-%d", port + 1);
00941         }
00942 
00943         /* RTP/TCP */
00944         else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
00945             snprintf(transport, sizeof(transport) - 1,
00946                      "%s/TCP;", trans_pref);
00947             if (rt->server_type == RTSP_SERVER_WMS)
00948                 av_strlcat(transport, "unicast;", sizeof(transport));
00949             av_strlcatf(transport, sizeof(transport),
00950                         "interleaved=%d-%d",
00951                         interleave, interleave + 1);
00952             interleave += 2;
00953         }
00954 
00955         else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) {
00956             snprintf(transport, sizeof(transport) - 1,
00957                      "%s/UDP;multicast", trans_pref);
00958         }
00959         if (rt->server_type == RTSP_SERVER_REAL ||
00960             rt->server_type == RTSP_SERVER_WMS)
00961             av_strlcat(transport, ";mode=play", sizeof(transport));
00962         snprintf(cmd, sizeof(cmd),
00963                  "SETUP %s RTSP/1.0\r\n"
00964                  "Transport: %s\r\n",
00965                  rtsp_st->control_url, transport);
00966         if (i == 0 && rt->server_type == RTSP_SERVER_REAL) {
00967             char real_res[41], real_csum[9];
00968             ff_rdt_calc_response_and_checksum(real_res, real_csum,
00969                                               real_challenge);
00970             av_strlcatf(cmd, sizeof(cmd),
00971                         "If-Match: %s\r\n"
00972                         "RealChallenge2: %s, sd=%s\r\n",
00973                         rt->session_id, real_res, real_csum);
00974         }
00975         rtsp_send_cmd(s, cmd, reply, NULL);
00976         if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) {
00977             err = 1;
00978             goto fail;
00979         } else if (reply->status_code != RTSP_STATUS_OK ||
00980                    reply->nb_transports != 1) {
00981             err = AVERROR_INVALIDDATA;
00982             goto fail;
00983         }
00984 
00985         /* XXX: same protocol for all streams is required */
00986         if (i > 0) {
00987             if (reply->transports[0].lower_transport != rt->lower_transport ||
00988                 reply->transports[0].transport != rt->transport) {
00989                 err = AVERROR_INVALIDDATA;
00990                 goto fail;
00991             }
00992         } else {
00993             rt->lower_transport = reply->transports[0].lower_transport;
00994             rt->transport = reply->transports[0].transport;
00995         }
00996 
00997         /* close RTP connection if not choosen */
00998         if (reply->transports[0].lower_transport != RTSP_LOWER_TRANSPORT_UDP &&
00999             (lower_transport == RTSP_LOWER_TRANSPORT_UDP)) {
01000             url_close(rtsp_st->rtp_handle);
01001             rtsp_st->rtp_handle = NULL;
01002         }
01003 
01004         switch(reply->transports[0].lower_transport) {
01005         case RTSP_LOWER_TRANSPORT_TCP:
01006             rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
01007             rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
01008             break;
01009 
01010         case RTSP_LOWER_TRANSPORT_UDP:
01011             {
01012                 char url[1024];
01013 
01014                 /* XXX: also use address if specified */
01015                 snprintf(url, sizeof(url), "rtp://%s:%d",
01016                          host, reply->transports[0].server_port_min);
01017                 if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
01018                     err = AVERROR_INVALIDDATA;
01019                     goto fail;
01020                 }
01021             }
01022             break;
01023         case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
01024             {
01025                 char url[1024];
01026                 struct in_addr in;
01027 
01028                 in.s_addr = htonl(reply->transports[0].destination);
01029                 snprintf(url, sizeof(url), "rtp://%s:%d?ttl=%d",
01030                          inet_ntoa(in),
01031                          reply->transports[0].port_min,
01032                          reply->transports[0].ttl);
01033                 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
01034                     err = AVERROR_INVALIDDATA;
01035                     goto fail;
01036                 }
01037             }
01038             break;
01039         }
01040 
01041         if ((err = rtsp_open_transport_ctx(s, rtsp_st)))
01042             goto fail;
01043     }
01044 
01045     if (rt->server_type == RTSP_SERVER_REAL)
01046         rt->need_subscription = 1;
01047 
01048     return 0;
01049 
01050 fail:
01051     for (i=0; i<rt->nb_rtsp_streams; i++) {
01052         if (rt->rtsp_streams[i]->rtp_handle) {
01053             url_close(rt->rtsp_streams[i]->rtp_handle);
01054             rt->rtsp_streams[i]->rtp_handle = NULL;
01055         }
01056     }
01057     return err;
01058 }
01059 
01060 static int rtsp_read_header(AVFormatContext *s,
01061                             AVFormatParameters *ap)
01062 {
01063     RTSPState *rt = s->priv_data;
01064     char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option;
01065     URLContext *rtsp_hd;
01066     int port, ret, err;
01067     RTSPMessageHeader reply1, *reply = &reply1;
01068     unsigned char *content = NULL;
01069     int lower_transport_mask = 0;
01070     char real_challenge[64];
01071 
01072     /* extract hostname and port */
01073     url_split(NULL, 0, NULL, 0,
01074               host, sizeof(host), &port, path, sizeof(path), s->filename);
01075     if (port < 0)
01076         port = RTSP_DEFAULT_PORT;
01077 
01078     /* search for options */
01079     option_list = strchr(path, '?');
01080     if (option_list) {
01081         /* remove the options from the path */
01082         *option_list++ = 0;
01083         while(option_list) {
01084             /* move the option pointer */
01085             option = option_list;
01086             option_list = strchr(option_list, '&');
01087             if (option_list)
01088                 *(option_list++) = 0;
01089             /* handle the options */
01090             if (strcmp(option, "udp") == 0)
01091                 lower_transport_mask = (1<< RTSP_LOWER_TRANSPORT_UDP);
01092             else if (strcmp(option, "multicast") == 0)
01093                 lower_transport_mask = (1<< RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
01094             else if (strcmp(option, "tcp") == 0)
01095                 lower_transport_mask = (1<< RTSP_LOWER_TRANSPORT_TCP);
01096         }
01097     }
01098 
01099     if (!lower_transport_mask)
01100         lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1;
01101 
01102     /* open the tcp connexion */
01103     snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
01104     if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
01105         return AVERROR(EIO);
01106     rt->rtsp_hd = rtsp_hd;
01107     rt->seq = 0;
01108 
01109     /* request options supported by the server; this also detects server type */
01110     for (rt->server_type = RTSP_SERVER_RTP;;) {
01111         snprintf(cmd, sizeof(cmd),
01112                  "OPTIONS %s RTSP/1.0\r\n", s->filename);
01113         if (rt->server_type == RTSP_SERVER_REAL)
01114             av_strlcat(cmd,
01124                        "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n"
01125                        "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n"
01126                        "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n"
01127                        "GUID: 00000000-0000-0000-0000-000000000000\r\n",
01128                        sizeof(cmd));
01129         rtsp_send_cmd(s, cmd, reply, NULL);
01130         if (reply->status_code != RTSP_STATUS_OK) {
01131             err = AVERROR_INVALIDDATA;
01132             goto fail;
01133         }
01134 
01135         /* detect server type if not standard-compliant RTP */
01136         if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) {
01137             rt->server_type = RTSP_SERVER_REAL;
01138             continue;
01139         } else if (!strncasecmp(reply->server, "WMServer/", 9)) {
01140             rt->server_type = RTSP_SERVER_WMS;
01141         } else if (rt->server_type == RTSP_SERVER_REAL) {
01142             strcpy(real_challenge, reply->real_challenge);
01143         }
01144         break;
01145     }
01146 
01147     /* describe the stream */
01148     snprintf(cmd, sizeof(cmd),
01149              "DESCRIBE %s RTSP/1.0\r\n"
01150              "Accept: application/sdp\r\n",
01151              s->filename);
01152     if (rt->server_type == RTSP_SERVER_REAL) {
01157         av_strlcat(cmd,
01158                    "Require: com.real.retain-entity-for-setup\r\n",
01159                    sizeof(cmd));
01160     }
01161     rtsp_send_cmd(s, cmd, reply, &content);
01162     if (!content) {
01163         err = AVERROR_INVALIDDATA;
01164         goto fail;
01165     }
01166     if (reply->status_code != RTSP_STATUS_OK) {
01167         err = AVERROR_INVALIDDATA;
01168         goto fail;
01169     }
01170 
01171     /* now we got the SDP description, we parse it */
01172     ret = sdp_parse(s, (const char *)content);
01173     av_freep(&content);
01174     if (ret < 0) {
01175         err = AVERROR_INVALIDDATA;
01176         goto fail;
01177     }
01178 
01179     do {
01180         int lower_transport = ff_log2_tab[lower_transport_mask & ~(lower_transport_mask - 1)];
01181 
01182         err = make_setup_request(s, host, port, lower_transport,
01183                                  rt->server_type == RTSP_SERVER_REAL ?
01184                                      real_challenge : NULL);
01185         if (err < 0)
01186             goto fail;
01187         lower_transport_mask &= ~(1 << lower_transport);
01188         if (lower_transport_mask == 0 && err == 1) {
01189             err = AVERROR(FF_NETERROR(EPROTONOSUPPORT));
01190             goto fail;
01191         }
01192     } while (err);
01193 
01194     rt->state = RTSP_STATE_IDLE;
01195     rt->seek_timestamp = 0; /* default is to start stream at position
01196                                zero */
01197     if (ap->initial_pause) {
01198         /* do not start immediately */
01199     } else {
01200         if (rtsp_read_play(s) < 0) {
01201             err = AVERROR_INVALIDDATA;
01202             goto fail;
01203         }
01204     }
01205     return 0;
01206  fail:
01207     rtsp_close_streams(rt);
01208     av_freep(&content);
01209     url_close(rt->rtsp_hd);
01210     return err;
01211 }
01212 
01213 static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
01214                            uint8_t *buf, int buf_size)
01215 {
01216     RTSPState *rt = s->priv_data;
01217     int id, len, i, ret;
01218     RTSPStream *rtsp_st;
01219 
01220 #ifdef DEBUG_RTP_TCP
01221     printf("tcp_read_packet:\n");
01222 #endif
01223  redo:
01224     for(;;) {
01225         ret = url_readbuf(rt->rtsp_hd, buf, 1);
01226 #ifdef DEBUG_RTP_TCP
01227         printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
01228 #endif
01229         if (ret != 1)
01230             return -1;
01231         if (buf[0] == '$')
01232             break;
01233     }
01234     ret = url_readbuf(rt->rtsp_hd, buf, 3);
01235     if (ret != 3)
01236         return -1;
01237     id = buf[0];
01238     len = AV_RB16(buf + 1);
01239 #ifdef DEBUG_RTP_TCP
01240     printf("id=%d len=%d\n", id, len);
01241 #endif
01242     if (len > buf_size || len < 12)
01243         goto redo;
01244     /* get the data */
01245     ret = url_readbuf(rt->rtsp_hd, buf, len);
01246     if (ret != len)
01247         return -1;
01248     if (rt->transport == RTSP_TRANSPORT_RDT &&
01249         ff_rdt_parse_header(buf, len, &id, NULL, NULL, NULL, NULL) < 0)
01250         return -1;
01251 
01252     /* find the matching stream */
01253     for(i = 0; i < rt->nb_rtsp_streams; i++) {
01254         rtsp_st = rt->rtsp_streams[i];
01255         if (id >= rtsp_st->interleaved_min &&
01256             id <= rtsp_st->interleaved_max)
01257             goto found;
01258     }
01259     goto redo;
01260  found:
01261     *prtsp_st = rtsp_st;
01262     return len;
01263 }
01264 
01265 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
01266                            uint8_t *buf, int buf_size)
01267 {
01268     RTSPState *rt = s->priv_data;
01269     RTSPStream *rtsp_st;
01270     fd_set rfds;
01271     int fd1, fd2, fd_max, n, i, ret;
01272     struct timeval tv;
01273 
01274     for(;;) {
01275         if (url_interrupt_cb())
01276             return AVERROR(EINTR);
01277         FD_ZERO(&rfds);
01278         fd_max = -1;
01279         for(i = 0; i < rt->nb_rtsp_streams; i++) {
01280             rtsp_st = rt->rtsp_streams[i];
01281             /* currently, we cannot probe RTCP handle because of blocking restrictions */
01282             rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
01283             if (fd1 > fd_max)
01284                 fd_max = fd1;
01285             FD_SET(fd1, &rfds);
01286         }
01287         tv.tv_sec = 0;
01288         tv.tv_usec = 100 * 1000;
01289         n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
01290         if (n > 0) {
01291             for(i = 0; i < rt->nb_rtsp_streams; i++) {
01292                 rtsp_st = rt->rtsp_streams[i];
01293                 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
01294                 if (FD_ISSET(fd1, &rfds)) {
01295                     ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
01296                     if (ret > 0) {
01297                         *prtsp_st = rtsp_st;
01298                         return ret;
01299                     }
01300                 }
01301             }
01302         }
01303     }
01304 }
01305 
01306 static int rtsp_read_packet(AVFormatContext *s,
01307                             AVPacket *pkt)
01308 {
01309     RTSPState *rt = s->priv_data;
01310     RTSPStream *rtsp_st;
01311     int ret, len;
01312     uint8_t buf[10 * RTP_MAX_PACKET_LENGTH];
01313 
01314     if (rt->server_type == RTSP_SERVER_REAL) {
01315         int i;
01316         RTSPMessageHeader reply1, *reply = &reply1;
01317         enum AVDiscard cache[MAX_STREAMS];
01318         char cmd[1024];
01319 
01320         for (i = 0; i < s->nb_streams; i++)
01321             cache[i] = s->streams[i]->discard;
01322 
01323         if (!rt->need_subscription) {
01324             if (memcmp (cache, rt->real_setup_cache,
01325                         sizeof(enum AVDiscard) * s->nb_streams)) {
01326                 av_strlcatf(cmd, sizeof(cmd),
01327                             "SET_PARAMETER %s RTSP/1.0\r\n"
01328                             "Unsubscribe: %s\r\n",
01329                             s->filename, rt->last_subscription);
01330                 rtsp_send_cmd(s, cmd, reply, NULL);
01331                 if (reply->status_code != RTSP_STATUS_OK)
01332                     return AVERROR_INVALIDDATA;
01333                 rt->need_subscription = 1;
01334             }
01335         }
01336 
01337         if (rt->need_subscription) {
01338             int r, rule_nr, first = 1;
01339 
01340             memcpy(rt->real_setup_cache, cache,
01341                    sizeof(enum AVDiscard) * s->nb_streams);
01342             rt->last_subscription[0] = 0;
01343 
01344             snprintf(cmd, sizeof(cmd),
01345                      "SET_PARAMETER %s RTSP/1.0\r\n"
01346                      "Subscribe: ",
01347                      s->filename);
01348             for (i = 0; i < rt->nb_rtsp_streams; i++) {
01349                 rule_nr = 0;
01350                 for (r = 0; r < s->nb_streams; r++) {
01351                     if (s->streams[r]->priv_data == rt->rtsp_streams[i]) {
01352                         if (s->streams[r]->discard != AVDISCARD_ALL) {
01353                             if (!first)
01354                                 av_strlcat(rt->last_subscription, ",",
01355                                            sizeof(rt->last_subscription));
01356                             ff_rdt_subscribe_rule(
01357                                 rt->last_subscription,
01358                                 sizeof(rt->last_subscription), i, rule_nr);
01359                             first = 0;
01360                         }
01361                         rule_nr++;
01362                     }
01363                 }
01364             }
01365             av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription);
01366             rtsp_send_cmd(s, cmd, reply, NULL);
01367             if (reply->status_code != RTSP_STATUS_OK)
01368                 return AVERROR_INVALIDDATA;
01369             rt->need_subscription = 0;
01370 
01371             if (rt->state == RTSP_STATE_PLAYING)
01372                 rtsp_read_play (s);
01373         }
01374     }
01375 
01376     /* get next frames from the same RTP packet */
01377     if (rt->cur_transport_priv) {
01378         if (rt->transport == RTSP_TRANSPORT_RDT)
01379             ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
01380         else
01381             ret = rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
01382         if (ret == 0) {
01383             rt->cur_transport_priv = NULL;
01384             return 0;
01385         } else if (ret == 1) {
01386             return 0;
01387         } else {
01388             rt->cur_transport_priv = NULL;
01389         }
01390     }
01391 
01392     /* read next RTP packet */
01393  redo:
01394     switch(rt->lower_transport) {
01395     default:
01396     case RTSP_LOWER_TRANSPORT_TCP:
01397         len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
01398         break;
01399     case RTSP_LOWER_TRANSPORT_UDP:
01400     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
01401         len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
01402         if (len >=0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP)
01403             rtp_check_and_send_back_rr(rtsp_st->transport_priv, len);
01404         break;
01405     }
01406     if (len < 0)
01407         return len;
01408     if (rt->transport == RTSP_TRANSPORT_RDT)
01409         ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
01410     else
01411         ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
01412     if (ret < 0)
01413         goto redo;
01414     if (ret == 1) {
01415         /* more packets may follow, so we save the RTP context */
01416         rt->cur_transport_priv = rtsp_st->transport_priv;
01417     }
01418     return 0;
01419 }
01420 
01421 static int rtsp_read_play(AVFormatContext *s)
01422 {
01423     RTSPState *rt = s->priv_data;
01424     RTSPMessageHeader reply1, *reply = &reply1;
01425     char cmd[1024];
01426 
01427     av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
01428 
01429     if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
01430         if (rt->state == RTSP_STATE_PAUSED) {
01431             snprintf(cmd, sizeof(cmd),
01432                      "PLAY %s RTSP/1.0\r\n",
01433                      s->filename);
01434         } else {
01435             snprintf(cmd, sizeof(cmd),
01436                      "PLAY %s RTSP/1.0\r\n"
01437                      "Range: npt=%0.3f-\r\n",
01438                      s->filename,
01439                      (double)rt->seek_timestamp / AV_TIME_BASE);
01440         }
01441         rtsp_send_cmd(s, cmd, reply, NULL);
01442         if (reply->status_code != RTSP_STATUS_OK) {
01443             return -1;
01444         }
01445     }
01446     rt->state = RTSP_STATE_PLAYING;
01447     return 0;
01448 }
01449 
01450 /* pause the stream */
01451 static int rtsp_read_pause(AVFormatContext *s)
01452 {
01453     RTSPState *rt = s->priv_data;
01454     RTSPMessageHeader reply1, *reply = &reply1;
01455     char cmd[1024];
01456 
01457     rt = s->priv_data;
01458 
01459     if (rt->state != RTSP_STATE_PLAYING)
01460         return 0;
01461     else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
01462         snprintf(cmd, sizeof(cmd),
01463                  "PAUSE %s RTSP/1.0\r\n",
01464                  s->filename);
01465         rtsp_send_cmd(s, cmd, reply, NULL);
01466         if (reply->status_code != RTSP_STATUS_OK) {
01467             return -1;
01468         }
01469     }
01470     rt->state = RTSP_STATE_PAUSED;
01471     return 0;
01472 }
01473 
01474 static int rtsp_read_seek(AVFormatContext *s, int stream_index,
01475                           int64_t timestamp, int flags)
01476 {
01477     RTSPState *rt = s->priv_data;
01478 
01479     rt->seek_timestamp = av_rescale_q(timestamp, s->streams[stream_index]->time_base, AV_TIME_BASE_Q);
01480     switch(rt->state) {
01481     default:
01482     case RTSP_STATE_IDLE:
01483         break;
01484     case RTSP_STATE_PLAYING:
01485         if (rtsp_read_play(s) != 0)
01486             return -1;
01487         break;
01488     case RTSP_STATE_PAUSED:
01489         rt->state = RTSP_STATE_IDLE;
01490         break;
01491     }
01492     return 0;
01493 }
01494 
01495 static int rtsp_read_close(AVFormatContext *s)
01496 {
01497     RTSPState *rt = s->priv_data;
01498     RTSPMessageHeader reply1, *reply = &reply1;
01499     char cmd[1024];
01500 
01501 #if 0
01502     /* NOTE: it is valid to flush the buffer here */
01503     if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
01504         url_fclose(&rt->rtsp_gb);
01505     }
01506 #endif
01507     snprintf(cmd, sizeof(cmd),
01508              "TEARDOWN %s RTSP/1.0\r\n",
01509              s->filename);
01510     rtsp_send_cmd(s, cmd, reply, NULL);
01511 
01512     rtsp_close_streams(rt);
01513     url_close(rt->rtsp_hd);
01514     return 0;
01515 }
01516 
01517 #if CONFIG_RTSP_DEMUXER
01518 AVInputFormat rtsp_demuxer = {
01519     "rtsp",
01520     NULL_IF_CONFIG_SMALL("RTSP input format"),
01521     sizeof(RTSPState),
01522     rtsp_probe,
01523     rtsp_read_header,
01524     rtsp_read_packet,
01525     rtsp_read_close,
01526     rtsp_read_seek,
01527     .flags = AVFMT_NOFILE,
01528     .read_play = rtsp_read_play,
01529     .read_pause = rtsp_read_pause,
01530 };
01531 #endif
01532 
01533 static int sdp_probe(AVProbeData *p1)
01534 {
01535     const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
01536 
01537     /* we look for a line beginning "c=IN IP4" */
01538     while (p < p_end && *p != '\0') {
01539         if (p + sizeof("c=IN IP4") - 1 < p_end && av_strstart(p, "c=IN IP4", NULL))
01540             return AVPROBE_SCORE_MAX / 2;
01541 
01542         while(p < p_end - 1 && *p != '\n') p++;
01543         if (++p >= p_end)
01544             break;
01545         if (*p == '\r')
01546             p++;
01547     }
01548     return 0;
01549 }
01550 
01551 #define SDP_MAX_SIZE 8192
01552 
01553 static int sdp_read_header(AVFormatContext *s,
01554                            AVFormatParameters *ap)
01555 {
01556     RTSPState *rt = s->priv_data;
01557     RTSPStream *rtsp_st;
01558     int size, i, err;
01559     char *content;
01560     char url[1024];
01561 
01562     /* read the whole sdp file */
01563     /* XXX: better loading */
01564     content = av_malloc(SDP_MAX_SIZE);
01565     size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1);
01566     if (size <= 0) {
01567         av_free(content);
01568         return AVERROR_INVALIDDATA;
01569     }
01570     content[size] ='\0';
01571 
01572     sdp_parse(s, content);
01573     av_free(content);
01574 
01575     /* open each RTP stream */
01576     for(i=0;i<rt->nb_rtsp_streams;i++) {
01577         rtsp_st = rt->rtsp_streams[i];
01578 
01579         snprintf(url, sizeof(url), "rtp://%s:%d?localport=%d&ttl=%d",
01580                  inet_ntoa(rtsp_st->sdp_ip),
01581                  rtsp_st->sdp_port,
01582                  rtsp_st->sdp_port,
01583                  rtsp_st->sdp_ttl);
01584         if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
01585             err = AVERROR_INVALIDDATA;
01586             goto fail;
01587         }
01588         if ((err = rtsp_open_transport_ctx(s, rtsp_st)))
01589             goto fail;
01590     }
01591     return 0;
01592  fail:
01593     rtsp_close_streams(rt);
01594     return err;
01595 }
01596 
01597 static int sdp_read_packet(AVFormatContext *s,
01598                             AVPacket *pkt)
01599 {
01600     return rtsp_read_packet(s, pkt);
01601 }
01602 
01603 static int sdp_read_close(AVFormatContext *s)
01604 {
01605     RTSPState *rt = s->priv_data;
01606     rtsp_close_streams(rt);
01607     return 0;
01608 }
01609 
01610 #if CONFIG_SDP_DEMUXER
01611 AVInputFormat sdp_demuxer = {
01612     "sdp",
01613     NULL_IF_CONFIG_SMALL("SDP"),
01614     sizeof(RTSPState),
01615     sdp_probe,
01616     sdp_read_header,
01617     sdp_read_packet,
01618     sdp_read_close,
01619 };
01620 #endif
01621 
01622 #if CONFIG_REDIR_DEMUXER
01623 /* dummy redirector format (used directly in av_open_input_file now) */
01624 static int redir_probe(AVProbeData *pd)
01625 {
01626     const char *p;
01627     p = pd->buf;
01628     while (redir_isspace(*p))
01629         p++;
01630     if (av_strstart(p, "http://", NULL) ||
01631         av_strstart(p, "rtsp://", NULL))
01632         return AVPROBE_SCORE_MAX;
01633     return 0;
01634 }
01635 
01636 static int redir_read_header(AVFormatContext *s, AVFormatParameters *ap)
01637 {
01638     char buf[4096], *q;
01639     int c;
01640     AVFormatContext *ic = NULL;
01641     ByteIOContext *f = s->pb;
01642 
01643     /* parse each URL and try to open it */
01644     c = url_fgetc(f);
01645     while (c != URL_EOF) {
01646         /* skip spaces */
01647         for(;;) {
01648             if (!redir_isspace(c))
01649                 break;
01650             c = url_fgetc(f);
01651         }
01652         if (c == URL_EOF)
01653             break;
01654         /* record url */
01655         q = buf;
01656         for(;;) {
01657             if (c == URL_EOF || redir_isspace(c))
01658                 break;
01659             if ((q - buf) < sizeof(buf) - 1)
01660                 *q++ = c;
01661             c = url_fgetc(f);
01662         }
01663         *q = '\0';
01664         //printf("URL='%s'\n", buf);
01665         /* try to open the media file */
01666         if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
01667             break;
01668     }
01669     if (!ic)
01670         return AVERROR(EIO);
01671 
01672     *s = *ic;
01673     url_fclose(f);
01674 
01675     return 0;
01676 }
01677 
01678 AVInputFormat redir_demuxer = {
01679     "redir",
01680     NULL_IF_CONFIG_SMALL("Redirector format"),
01681     0,
01682     redir_probe,
01683     redir_read_header,
01684     NULL,
01685     NULL,
01686 };
01687 #endif

Generated on Sat Feb 16 2013 09:23:15 for ffmpeg by  doxygen 1.7.1