00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022
00023 #include <sys/time.h>
00024 #include <unistd.h>
00025 #include "network.h"
00026 #include "avstring.h"
00027 #include "rtsp.h"
00028
00029 #include "rtp_internal.h"
00030
00031
00032
00033
00034 enum RTSPClientState {
00035 RTSP_STATE_IDLE,
00036 RTSP_STATE_PLAYING,
00037 RTSP_STATE_PAUSED,
00038 };
00039
00040 typedef struct RTSPState {
00041 URLContext *rtsp_hd;
00042 int nb_rtsp_streams;
00043 struct RTSPStream **rtsp_streams;
00044
00045 enum RTSPClientState state;
00046 int64_t seek_timestamp;
00047
00048
00049
00050 int seq;
00051 char session_id[512];
00052 enum RTSPProtocol protocol;
00053 char last_reply[2048];
00054 RTPDemuxContext *cur_rtp;
00055 } RTSPState;
00056
00057 typedef struct RTSPStream {
00058 URLContext *rtp_handle;
00059 RTPDemuxContext *rtp_ctx;
00060
00061 int stream_index;
00062 int interleaved_min, interleaved_max;
00063 char control_url[1024];
00064
00065 int sdp_port;
00066 struct in_addr sdp_ip;
00067 int sdp_ttl;
00068 int sdp_payload_type;
00069 rtp_payload_data_t rtp_payload_data;
00070
00071 RTPDynamicProtocolHandler *dynamic_handler;
00072 void *dynamic_protocol_context;
00073 } RTSPStream;
00074
00075 static int rtsp_read_play(AVFormatContext *s);
00076
00077
00078
00079
00080 #if LIBAVFORMAT_VERSION_INT < (53 << 16)
00081 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_UDP);
00082 #endif
00083
00084 static int rtsp_probe(AVProbeData *p)
00085 {
00086 if (av_strstart(p->filename, "rtsp:", NULL))
00087 return AVPROBE_SCORE_MAX;
00088 return 0;
00089 }
00090
00091 static int redir_isspace(int c)
00092 {
00093 return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
00094 }
00095
00096 static void skip_spaces(const char **pp)
00097 {
00098 const char *p;
00099 p = *pp;
00100 while (redir_isspace(*p))
00101 p++;
00102 *pp = p;
00103 }
00104
00105 static void get_word_sep(char *buf, int buf_size, const char *sep,
00106 const char **pp)
00107 {
00108 const char *p;
00109 char *q;
00110
00111 p = *pp;
00112 if (*p == '/')
00113 p++;
00114 skip_spaces(&p);
00115 q = buf;
00116 while (!strchr(sep, *p) && *p != '\0') {
00117 if ((q - buf) < buf_size - 1)
00118 *q++ = *p;
00119 p++;
00120 }
00121 if (buf_size > 0)
00122 *q = '\0';
00123 *pp = p;
00124 }
00125
00126 static void get_word(char *buf, int buf_size, const char **pp)
00127 {
00128 const char *p;
00129 char *q;
00130
00131 p = *pp;
00132 skip_spaces(&p);
00133 q = buf;
00134 while (!redir_isspace(*p) && *p != '\0') {
00135 if ((q - buf) < buf_size - 1)
00136 *q++ = *p;
00137 p++;
00138 }
00139 if (buf_size > 0)
00140 *q = '\0';
00141 *pp = p;
00142 }
00143
00144
00145
00146 static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payload_type, const char *p)
00147 {
00148 char buf[256];
00149 int i;
00150 AVCodec *c;
00151 const char *c_name;
00152
00153
00154
00155 get_word_sep(buf, sizeof(buf), "/", &p);
00156 if (payload_type >= RTP_PT_PRIVATE) {
00157 RTPDynamicProtocolHandler *handler= RTPFirstDynamicPayloadHandler;
00158 while(handler) {
00159 if (!strcmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) {
00160 codec->codec_id = handler->codec_id;
00161 rtsp_st->dynamic_handler= handler;
00162 if(handler->open) {
00163 rtsp_st->dynamic_protocol_context= handler->open();
00164 }
00165 break;
00166 }
00167 handler= handler->next;
00168 }
00169 } else {
00170
00171
00172 codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type);
00173 }
00174
00175 c = avcodec_find_decoder(codec->codec_id);
00176 if (c && c->name)
00177 c_name = c->name;
00178 else
00179 c_name = (char *)NULL;
00180
00181 if (c_name) {
00182 get_word_sep(buf, sizeof(buf), "/", &p);
00183 i = atoi(buf);
00184 switch (codec->codec_type) {
00185 case CODEC_TYPE_AUDIO:
00186 av_log(codec, AV_LOG_DEBUG, " audio codec set to : %s\n", c_name);
00187 codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE;
00188 codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS;
00189 if (i > 0) {
00190 codec->sample_rate = i;
00191 get_word_sep(buf, sizeof(buf), "/", &p);
00192 i = atoi(buf);
00193 if (i > 0)
00194 codec->channels = i;
00195
00196
00197 }
00198 av_log(codec, AV_LOG_DEBUG, " audio samplerate set to : %i\n", codec->sample_rate);
00199 av_log(codec, AV_LOG_DEBUG, " audio channels set to : %i\n", codec->channels);
00200 break;
00201 case CODEC_TYPE_VIDEO:
00202 av_log(codec, AV_LOG_DEBUG, " video codec set to : %s\n", c_name);
00203 break;
00204 default:
00205 break;
00206 }
00207 return 0;
00208 }
00209
00210 return -1;
00211 }
00212
00213
00214 static int hex_to_data(uint8_t *data, const char *p)
00215 {
00216 int c, len, v;
00217
00218 len = 0;
00219 v = 1;
00220 for(;;) {
00221 skip_spaces(&p);
00222 if (p == '\0')
00223 break;
00224 c = toupper((unsigned char)*p++);
00225 if (c >= '0' && c <= '9')
00226 c = c - '0';
00227 else if (c >= 'A' && c <= 'F')
00228 c = c - 'A' + 10;
00229 else
00230 break;
00231 v = (v << 4) | c;
00232 if (v & 0x100) {
00233 if (data)
00234 data[len] = v;
00235 len++;
00236 v = 1;
00237 }
00238 }
00239 return len;
00240 }
00241
00242 static void sdp_parse_fmtp_config(AVCodecContext *codec, char *attr, char *value)
00243 {
00244 switch (codec->codec_id) {
00245 case CODEC_ID_MPEG4:
00246 case CODEC_ID_AAC:
00247 if (!strcmp(attr, "config")) {
00248
00249 int len = hex_to_data(NULL, value);
00250 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
00251 if (!codec->extradata)
00252 return;
00253 codec->extradata_size = len;
00254 hex_to_data(codec->extradata, value);
00255 }
00256 break;
00257 default:
00258 break;
00259 }
00260 return;
00261 }
00262
00263 typedef struct attrname_map
00264 {
00265 const char *str;
00266 uint16_t type;
00267 uint32_t offset;
00268 } attrname_map_t;
00269
00270
00271 #define ATTR_NAME_TYPE_INT 0
00272 #define ATTR_NAME_TYPE_STR 1
00273 static attrname_map_t attr_names[]=
00274 {
00275 {"SizeLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, sizelength)},
00276 {"IndexLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, indexlength)},
00277 {"IndexDeltaLength", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, indexdeltalength)},
00278 {"profile-level-id", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, profile_level_id)},
00279 {"StreamType", ATTR_NAME_TYPE_INT, offsetof(rtp_payload_data_t, streamtype)},
00280 {"mode", ATTR_NAME_TYPE_STR, offsetof(rtp_payload_data_t, mode)},
00281 {NULL, -1, -1},
00282 };
00283
00287 int rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, char *value, int value_size)
00288 {
00289 skip_spaces(p);
00290 if(**p)
00291 {
00292 get_word_sep(attr, attr_size, "=", p);
00293 if (**p == '=')
00294 (*p)++;
00295 get_word_sep(value, value_size, ";", p);
00296 if (**p == ';')
00297 (*p)++;
00298 return 1;
00299 }
00300 return 0;
00301 }
00302
00303
00304 static void sdp_parse_fmtp(AVStream *st, const char *p)
00305 {
00306 char attr[256];
00307 char value[4096];
00308 int i;
00309
00310 RTSPStream *rtsp_st = st->priv_data;
00311 AVCodecContext *codec = st->codec;
00312 rtp_payload_data_t *rtp_payload_data = &rtsp_st->rtp_payload_data;
00313
00314
00315 while(rtsp_next_attr_and_value(&p, attr, sizeof(attr), value, sizeof(value)))
00316 {
00317
00318 sdp_parse_fmtp_config(codec, attr, value);
00319
00320 for (i = 0; attr_names[i].str; ++i) {
00321 if (!strcasecmp(attr, attr_names[i].str)) {
00322 if (attr_names[i].type == ATTR_NAME_TYPE_INT)
00323 *(int *)((char *)rtp_payload_data + attr_names[i].offset) = atoi(value);
00324 else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
00325 *(char **)((char *)rtp_payload_data + attr_names[i].offset) = av_strdup(value);
00326 }
00327 }
00328 }
00329 }
00330
00335 static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end)
00336 {
00337 char buf[256];
00338
00339 skip_spaces(&p);
00340 if (!av_stristart(p, "npt=", &p))
00341 return;
00342
00343 *start = AV_NOPTS_VALUE;
00344 *end = AV_NOPTS_VALUE;
00345
00346 get_word_sep(buf, sizeof(buf), "-", &p);
00347 *start = parse_date(buf, 1);
00348 if (*p == '-') {
00349 p++;
00350 get_word_sep(buf, sizeof(buf), "-", &p);
00351 *end = parse_date(buf, 1);
00352 }
00353
00354
00355 }
00356
00357 typedef struct SDPParseState {
00358
00359 struct in_addr default_ip;
00360 int default_ttl;
00361 } SDPParseState;
00362
00363 static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
00364 int letter, const char *buf)
00365 {
00366 RTSPState *rt = s->priv_data;
00367 char buf1[64], st_type[64];
00368 const char *p;
00369 int codec_type, payload_type, i;
00370 AVStream *st;
00371 RTSPStream *rtsp_st;
00372 struct in_addr sdp_ip;
00373 int ttl;
00374
00375 #ifdef DEBUG
00376 printf("sdp: %c='%s'\n", letter, buf);
00377 #endif
00378
00379 p = buf;
00380 switch(letter) {
00381 case 'c':
00382 get_word(buf1, sizeof(buf1), &p);
00383 if (strcmp(buf1, "IN") != 0)
00384 return;
00385 get_word(buf1, sizeof(buf1), &p);
00386 if (strcmp(buf1, "IP4") != 0)
00387 return;
00388 get_word_sep(buf1, sizeof(buf1), "/", &p);
00389 if (inet_aton(buf1, &sdp_ip) == 0)
00390 return;
00391 ttl = 16;
00392 if (*p == '/') {
00393 p++;
00394 get_word_sep(buf1, sizeof(buf1), "/", &p);
00395 ttl = atoi(buf1);
00396 }
00397 if (s->nb_streams == 0) {
00398 s1->default_ip = sdp_ip;
00399 s1->default_ttl = ttl;
00400 } else {
00401 st = s->streams[s->nb_streams - 1];
00402 rtsp_st = st->priv_data;
00403 rtsp_st->sdp_ip = sdp_ip;
00404 rtsp_st->sdp_ttl = ttl;
00405 }
00406 break;
00407 case 's':
00408 av_strlcpy(s->title, p, sizeof(s->title));
00409 break;
00410 case 'i':
00411 if (s->nb_streams == 0) {
00412 av_strlcpy(s->comment, p, sizeof(s->comment));
00413 break;
00414 }
00415 break;
00416 case 'm':
00417
00418 get_word(st_type, sizeof(st_type), &p);
00419 if (!strcmp(st_type, "audio")) {
00420 codec_type = CODEC_TYPE_AUDIO;
00421 } else if (!strcmp(st_type, "video")) {
00422 codec_type = CODEC_TYPE_VIDEO;
00423 } else {
00424 return;
00425 }
00426 rtsp_st = av_mallocz(sizeof(RTSPStream));
00427 if (!rtsp_st)
00428 return;
00429 rtsp_st->stream_index = -1;
00430 dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st);
00431
00432 rtsp_st->sdp_ip = s1->default_ip;
00433 rtsp_st->sdp_ttl = s1->default_ttl;
00434
00435 get_word(buf1, sizeof(buf1), &p);
00436 rtsp_st->sdp_port = atoi(buf1);
00437
00438 get_word(buf1, sizeof(buf1), &p);
00439
00440
00441 get_word(buf1, sizeof(buf1), &p);
00442 rtsp_st->sdp_payload_type = atoi(buf1);
00443
00444 if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) {
00445
00446 } else {
00447 st = av_new_stream(s, 0);
00448 if (!st)
00449 return;
00450 st->priv_data = rtsp_st;
00451 rtsp_st->stream_index = st->index;
00452 st->codec->codec_type = codec_type;
00453 if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
00454
00455 rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
00456 }
00457 }
00458
00459 av_strlcpy(rtsp_st->control_url, s->filename, sizeof(rtsp_st->control_url));
00460 break;
00461 case 'a':
00462 if (av_strstart(p, "control:", &p) && s->nb_streams > 0) {
00463 char proto[32];
00464
00465 st = s->streams[s->nb_streams - 1];
00466 rtsp_st = st->priv_data;
00467
00468
00469 url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p);
00470 if (proto[0] == '\0') {
00471
00472 av_strlcat(rtsp_st->control_url, "/", sizeof(rtsp_st->control_url));
00473 av_strlcat(rtsp_st->control_url, p, sizeof(rtsp_st->control_url));
00474 } else {
00475 av_strlcpy(rtsp_st->control_url, p, sizeof(rtsp_st->control_url));
00476 }
00477 } else if (av_strstart(p, "rtpmap:", &p)) {
00478
00479 get_word(buf1, sizeof(buf1), &p);
00480 payload_type = atoi(buf1);
00481 for(i = 0; i < s->nb_streams;i++) {
00482 st = s->streams[i];
00483 rtsp_st = st->priv_data;
00484 if (rtsp_st->sdp_payload_type == payload_type) {
00485 sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p);
00486 }
00487 }
00488 } else if (av_strstart(p, "fmtp:", &p)) {
00489
00490 get_word(buf1, sizeof(buf1), &p);
00491 payload_type = atoi(buf1);
00492 for(i = 0; i < s->nb_streams;i++) {
00493 st = s->streams[i];
00494 rtsp_st = st->priv_data;
00495 if (rtsp_st->sdp_payload_type == payload_type) {
00496 if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
00497 if(!rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf)) {
00498 sdp_parse_fmtp(st, p);
00499 }
00500 } else {
00501 sdp_parse_fmtp(st, p);
00502 }
00503 }
00504 }
00505 } else if(av_strstart(p, "framesize:", &p)) {
00506
00507 get_word(buf1, sizeof(buf1), &p);
00508 payload_type = atoi(buf1);
00509 for(i = 0; i < s->nb_streams;i++) {
00510 st = s->streams[i];
00511 rtsp_st = st->priv_data;
00512 if (rtsp_st->sdp_payload_type == payload_type) {
00513 if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) {
00514 rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf);
00515 }
00516 }
00517 }
00518 } else if(av_strstart(p, "range:", &p)) {
00519 int64_t start, end;
00520
00521
00522 rtsp_parse_range_npt(p, &start, &end);
00523 s->start_time= start;
00524 s->duration= (end==AV_NOPTS_VALUE)?AV_NOPTS_VALUE:end-start;
00525 }
00526 break;
00527 }
00528 }
00529
00530 static int sdp_parse(AVFormatContext *s, const char *content)
00531 {
00532 const char *p;
00533 int letter;
00534 char buf[1024], *q;
00535 SDPParseState sdp_parse_state, *s1 = &sdp_parse_state;
00536
00537 memset(s1, 0, sizeof(SDPParseState));
00538 p = content;
00539 for(;;) {
00540 skip_spaces(&p);
00541 letter = *p;
00542 if (letter == '\0')
00543 break;
00544 p++;
00545 if (*p != '=')
00546 goto next_line;
00547 p++;
00548
00549 q = buf;
00550 while (*p != '\n' && *p != '\r' && *p != '\0') {
00551 if ((q - buf) < sizeof(buf) - 1)
00552 *q++ = *p;
00553 p++;
00554 }
00555 *q = '\0';
00556 sdp_parse_line(s, s1, letter, buf);
00557 next_line:
00558 while (*p != '\n' && *p != '\0')
00559 p++;
00560 if (*p == '\n')
00561 p++;
00562 }
00563 return 0;
00564 }
00565
00566 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
00567 {
00568 const char *p;
00569 int v;
00570
00571 p = *pp;
00572 skip_spaces(&p);
00573 v = strtol(p, (char **)&p, 10);
00574 if (*p == '-') {
00575 p++;
00576 *min_ptr = v;
00577 v = strtol(p, (char **)&p, 10);
00578 *max_ptr = v;
00579 } else {
00580 *min_ptr = v;
00581 *max_ptr = v;
00582 }
00583 *pp = p;
00584 }
00585
00586
00587 static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
00588 {
00589 char transport_protocol[16];
00590 char profile[16];
00591 char lower_transport[16];
00592 char parameter[16];
00593 RTSPTransportField *th;
00594 char buf[256];
00595
00596 reply->nb_transports = 0;
00597
00598 for(;;) {
00599 skip_spaces(&p);
00600 if (*p == '\0')
00601 break;
00602
00603 th = &reply->transports[reply->nb_transports];
00604
00605 get_word_sep(transport_protocol, sizeof(transport_protocol),
00606 "/", &p);
00607 if (*p == '/')
00608 p++;
00609 if (!strcasecmp (transport_protocol, "rtp")) {
00610 get_word_sep(profile, sizeof(profile), "/;,", &p);
00611 lower_transport[0] = '\0';
00612
00613 if (*p == '/') {
00614 p++;
00615 get_word_sep(lower_transport, sizeof(lower_transport),
00616 ";,", &p);
00617 }
00618 } else if (!strcasecmp (transport_protocol, "x-pn-tng")) {
00619
00620 get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p);
00621 profile[0] = '\0';
00622 }
00623 if (!strcasecmp(lower_transport, "TCP"))
00624 th->protocol = RTSP_PROTOCOL_RTP_TCP;
00625 else
00626 th->protocol = RTSP_PROTOCOL_RTP_UDP;
00627
00628 if (*p == ';')
00629 p++;
00630
00631 while (*p != '\0' && *p != ',') {
00632 get_word_sep(parameter, sizeof(parameter), "=;,", &p);
00633 if (!strcmp(parameter, "port")) {
00634 if (*p == '=') {
00635 p++;
00636 rtsp_parse_range(&th->port_min, &th->port_max, &p);
00637 }
00638 } else if (!strcmp(parameter, "client_port")) {
00639 if (*p == '=') {
00640 p++;
00641 rtsp_parse_range(&th->client_port_min,
00642 &th->client_port_max, &p);
00643 }
00644 } else if (!strcmp(parameter, "server_port")) {
00645 if (*p == '=') {
00646 p++;
00647 rtsp_parse_range(&th->server_port_min,
00648 &th->server_port_max, &p);
00649 }
00650 } else if (!strcmp(parameter, "interleaved")) {
00651 if (*p == '=') {
00652 p++;
00653 rtsp_parse_range(&th->interleaved_min,
00654 &th->interleaved_max, &p);
00655 }
00656 } else if (!strcmp(parameter, "multicast")) {
00657 if (th->protocol == RTSP_PROTOCOL_RTP_UDP)
00658 th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
00659 } else if (!strcmp(parameter, "ttl")) {
00660 if (*p == '=') {
00661 p++;
00662 th->ttl = strtol(p, (char **)&p, 10);
00663 }
00664 } else if (!strcmp(parameter, "destination")) {
00665 struct in_addr ipaddr;
00666
00667 if (*p == '=') {
00668 p++;
00669 get_word_sep(buf, sizeof(buf), ";,", &p);
00670 if (inet_aton(buf, &ipaddr))
00671 th->destination = ntohl(ipaddr.s_addr);
00672 }
00673 }
00674 while (*p != ';' && *p != '\0' && *p != ',')
00675 p++;
00676 if (*p == ';')
00677 p++;
00678 }
00679 if (*p == ',')
00680 p++;
00681
00682 reply->nb_transports++;
00683 }
00684 }
00685
00686 void rtsp_parse_line(RTSPHeader *reply, const char *buf)
00687 {
00688 const char *p;
00689
00690
00691 p = buf;
00692 if (av_stristart(p, "Session:", &p)) {
00693 get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
00694 } else if (av_stristart(p, "Content-Length:", &p)) {
00695 reply->content_length = strtol(p, NULL, 10);
00696 } else if (av_stristart(p, "Transport:", &p)) {
00697 rtsp_parse_transport(reply, p);
00698 } else if (av_stristart(p, "CSeq:", &p)) {
00699 reply->seq = strtol(p, NULL, 10);
00700 } else if (av_stristart(p, "Range:", &p)) {
00701 rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end);
00702 }
00703 }
00704
00705 static int url_readbuf(URLContext *h, unsigned char *buf, int size)
00706 {
00707 int ret, len;
00708
00709 len = 0;
00710 while (len < size) {
00711 ret = url_read(h, buf+len, size-len);
00712 if (ret < 1)
00713 return ret;
00714 len += ret;
00715 }
00716 return len;
00717 }
00718
00719
00720 static void rtsp_skip_packet(AVFormatContext *s)
00721 {
00722 RTSPState *rt = s->priv_data;
00723 int ret, len, len1;
00724 uint8_t buf[1024];
00725
00726 ret = url_readbuf(rt->rtsp_hd, buf, 3);
00727 if (ret != 3)
00728 return;
00729 len = AV_RB16(buf + 1);
00730 #ifdef DEBUG
00731 printf("skipping RTP packet len=%d\n", len);
00732 #endif
00733
00734 while (len > 0) {
00735 len1 = len;
00736 if (len1 > sizeof(buf))
00737 len1 = sizeof(buf);
00738 ret = url_readbuf(rt->rtsp_hd, buf, len1);
00739 if (ret != len1)
00740 return;
00741 len -= len1;
00742 }
00743 }
00744
00745 static void rtsp_send_cmd(AVFormatContext *s,
00746 const char *cmd, RTSPHeader *reply,
00747 unsigned char **content_ptr)
00748 {
00749 RTSPState *rt = s->priv_data;
00750 char buf[4096], buf1[1024], *q;
00751 unsigned char ch;
00752 const char *p;
00753 int content_length, line_count;
00754 unsigned char *content = NULL;
00755
00756 memset(reply, 0, sizeof(RTSPHeader));
00757
00758 rt->seq++;
00759 av_strlcpy(buf, cmd, sizeof(buf));
00760 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
00761 av_strlcat(buf, buf1, sizeof(buf));
00762 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
00763 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
00764 av_strlcat(buf, buf1, sizeof(buf));
00765 }
00766 av_strlcat(buf, "\r\n", sizeof(buf));
00767 #ifdef DEBUG
00768 printf("Sending:\n%s--\n", buf);
00769 #endif
00770 url_write(rt->rtsp_hd, buf, strlen(buf));
00771
00772
00773 line_count = 0;
00774 rt->last_reply[0] = '\0';
00775 for(;;) {
00776 q = buf;
00777 for(;;) {
00778 if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1)
00779 break;
00780 if (ch == '\n')
00781 break;
00782 if (ch == '$') {
00783
00784 rtsp_skip_packet(s);
00785 } else if (ch != '\r') {
00786 if ((q - buf) < sizeof(buf) - 1)
00787 *q++ = ch;
00788 }
00789 }
00790 *q = '\0';
00791 #ifdef DEBUG
00792 printf("line='%s'\n", buf);
00793 #endif
00794
00795 if (buf[0] == '\0')
00796 break;
00797 p = buf;
00798 if (line_count == 0) {
00799
00800 get_word(buf1, sizeof(buf1), &p);
00801 get_word(buf1, sizeof(buf1), &p);
00802 reply->status_code = atoi(buf1);
00803 } else {
00804 rtsp_parse_line(reply, p);
00805 av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
00806 av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply));
00807 }
00808 line_count++;
00809 }
00810
00811 if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
00812 av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
00813
00814 content_length = reply->content_length;
00815 if (content_length > 0) {
00816
00817 content = av_malloc(content_length + 1);
00818 (void)url_readbuf(rt->rtsp_hd, content, content_length);
00819 content[content_length] = '\0';
00820 }
00821 if (content_ptr)
00822 *content_ptr = content;
00823 else
00824 av_free(content);
00825 }
00826
00827
00828
00829 static void rtsp_close_streams(RTSPState *rt)
00830 {
00831 int i;
00832 RTSPStream *rtsp_st;
00833
00834 for(i=0;i<rt->nb_rtsp_streams;i++) {
00835 rtsp_st = rt->rtsp_streams[i];
00836 if (rtsp_st) {
00837 if (rtsp_st->rtp_ctx)
00838 rtp_parse_close(rtsp_st->rtp_ctx);
00839 if (rtsp_st->rtp_handle)
00840 url_close(rtsp_st->rtp_handle);
00841 if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
00842 rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
00843 }
00844 av_free(rtsp_st);
00845 }
00846 av_free(rt->rtsp_streams);
00847 }
00848
00849 static int rtsp_read_header(AVFormatContext *s,
00850 AVFormatParameters *ap)
00851 {
00852 RTSPState *rt = s->priv_data;
00853 char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option;
00854 URLContext *rtsp_hd;
00855 int port, i, j, ret, err;
00856 RTSPHeader reply1, *reply = &reply1;
00857 unsigned char *content = NULL;
00858 RTSPStream *rtsp_st;
00859 int protocol_mask = 0;
00860 AVStream *st;
00861
00862
00863 url_split(NULL, 0, NULL, 0,
00864 host, sizeof(host), &port, path, sizeof(path), s->filename);
00865 if (port < 0)
00866 port = RTSP_DEFAULT_PORT;
00867
00868
00869 option_list = strchr(path, '?');
00870 if (option_list) {
00871
00872 *option_list++ = 0;
00873 while(option_list) {
00874
00875 option = option_list;
00876 option_list = strchr(option_list, '&');
00877 if (option_list)
00878 *(option_list++) = 0;
00879
00880 if (strcmp(option, "udp") == 0)
00881 protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP);
00882 else if (strcmp(option, "multicast") == 0)
00883 protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP_MULTICAST);
00884 else if (strcmp(option, "tcp") == 0)
00885 protocol_mask = (1<< RTSP_PROTOCOL_RTP_TCP);
00886 }
00887 }
00888
00889 if (!protocol_mask)
00890 protocol_mask = rtsp_default_protocols;
00891
00892
00893 snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
00894 if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
00895 return AVERROR(EIO);
00896 rt->rtsp_hd = rtsp_hd;
00897 rt->seq = 0;
00898
00899
00900 snprintf(cmd, sizeof(cmd),
00901 "DESCRIBE %s RTSP/1.0\r\n"
00902 "Accept: application/sdp\r\n",
00903 s->filename);
00904 rtsp_send_cmd(s, cmd, reply, &content);
00905 if (!content) {
00906 err = AVERROR_INVALIDDATA;
00907 goto fail;
00908 }
00909 if (reply->status_code != RTSP_STATUS_OK) {
00910 err = AVERROR_INVALIDDATA;
00911 goto fail;
00912 }
00913
00914
00915 ret = sdp_parse(s, (const char *)content);
00916 av_freep(&content);
00917 if (ret < 0) {
00918 err = AVERROR_INVALIDDATA;
00919 goto fail;
00920 }
00921
00922
00923
00924
00925
00926 for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
00927 char transport[2048];
00928
00929 rtsp_st = rt->rtsp_streams[i];
00930
00931
00932 transport[0] = '\0';
00933
00934
00935 if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) {
00936 char buf[256];
00937
00938
00939 if (RTSP_RTP_PORT_MIN != 0) {
00940 while(j <= RTSP_RTP_PORT_MAX) {
00941 snprintf(buf, sizeof(buf), "rtp://%s?localport=%d", host, j);
00942 j += 2;
00943 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) {
00944 goto rtp_opened;
00945 }
00946 }
00947 }
00948
00949
00950
00951
00952
00953
00954
00955
00956 rtp_opened:
00957 port = rtp_get_local_port(rtsp_st->rtp_handle);
00958 if (transport[0] != '\0')
00959 av_strlcat(transport, ",", sizeof(transport));
00960 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
00961 "RTP/AVP/UDP;unicast;client_port=%d-%d",
00962 port, port + 1);
00963 }
00964
00965
00966 else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {
00967 if (transport[0] != '\0')
00968 av_strlcat(transport, ",", sizeof(transport));
00969 snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
00970 "RTP/AVP/TCP");
00971 }
00972
00973 else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {
00974 if (transport[0] != '\0')
00975 av_strlcat(transport, ",", sizeof(transport));
00976 snprintf(transport + strlen(transport),
00977 sizeof(transport) - strlen(transport) - 1,
00978 "RTP/AVP/UDP;multicast");
00979 }
00980 snprintf(cmd, sizeof(cmd),
00981 "SETUP %s RTSP/1.0\r\n"
00982 "Transport: %s\r\n",
00983 rtsp_st->control_url, transport);
00984 rtsp_send_cmd(s, cmd, reply, NULL);
00985 if (reply->status_code != RTSP_STATUS_OK ||
00986 reply->nb_transports != 1) {
00987 err = AVERROR_INVALIDDATA;
00988 goto fail;
00989 }
00990
00991
00992 if (i > 0) {
00993 if (reply->transports[0].protocol != rt->protocol) {
00994 err = AVERROR_INVALIDDATA;
00995 goto fail;
00996 }
00997 } else {
00998 rt->protocol = reply->transports[0].protocol;
00999 }
01000
01001
01002 if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP &&
01003 (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) {
01004 url_close(rtsp_st->rtp_handle);
01005 rtsp_st->rtp_handle = NULL;
01006 }
01007
01008 switch(reply->transports[0].protocol) {
01009 case RTSP_PROTOCOL_RTP_TCP:
01010 rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
01011 rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
01012 break;
01013
01014 case RTSP_PROTOCOL_RTP_UDP:
01015 {
01016 char url[1024];
01017
01018
01019 snprintf(url, sizeof(url), "rtp://%s:%d",
01020 host, reply->transports[0].server_port_min);
01021 if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
01022 err = AVERROR_INVALIDDATA;
01023 goto fail;
01024 }
01025 }
01026 break;
01027 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
01028 {
01029 char url[1024];
01030 struct in_addr in;
01031
01032 in.s_addr = htonl(reply->transports[0].destination);
01033 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
01034 inet_ntoa(in),
01035 reply->transports[0].port_min,
01036 reply->transports[0].ttl);
01037 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
01038 err = AVERROR_INVALIDDATA;
01039 goto fail;
01040 }
01041 }
01042 break;
01043 }
01044
01045 st = NULL;
01046 if (rtsp_st->stream_index >= 0)
01047 st = s->streams[rtsp_st->stream_index];
01048 if (!st)
01049 s->ctx_flags |= AVFMTCTX_NOHEADER;
01050 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
01051
01052 if (!rtsp_st->rtp_ctx) {
01053 err = AVERROR(ENOMEM);
01054 goto fail;
01055 } else {
01056 if(rtsp_st->dynamic_handler) {
01057 rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
01058 rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
01059 }
01060 }
01061 }
01062
01063 rt->state = RTSP_STATE_IDLE;
01064 rt->seek_timestamp = 0;
01065
01066 if (ap->initial_pause) {
01067
01068 } else {
01069 if (rtsp_read_play(s) < 0) {
01070 err = AVERROR_INVALIDDATA;
01071 goto fail;
01072 }
01073 }
01074 return 0;
01075 fail:
01076 rtsp_close_streams(rt);
01077 av_freep(&content);
01078 url_close(rt->rtsp_hd);
01079 return err;
01080 }
01081
01082 static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
01083 uint8_t *buf, int buf_size)
01084 {
01085 RTSPState *rt = s->priv_data;
01086 int id, len, i, ret;
01087 RTSPStream *rtsp_st;
01088
01089 #ifdef DEBUG_RTP_TCP
01090 printf("tcp_read_packet:\n");
01091 #endif
01092 redo:
01093 for(;;) {
01094 ret = url_readbuf(rt->rtsp_hd, buf, 1);
01095 #ifdef DEBUG_RTP_TCP
01096 printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
01097 #endif
01098 if (ret != 1)
01099 return -1;
01100 if (buf[0] == '$')
01101 break;
01102 }
01103 ret = url_readbuf(rt->rtsp_hd, buf, 3);
01104 if (ret != 3)
01105 return -1;
01106 id = buf[0];
01107 len = AV_RB16(buf + 1);
01108 #ifdef DEBUG_RTP_TCP
01109 printf("id=%d len=%d\n", id, len);
01110 #endif
01111 if (len > buf_size || len < 12)
01112 goto redo;
01113
01114 ret = url_readbuf(rt->rtsp_hd, buf, len);
01115 if (ret != len)
01116 return -1;
01117
01118
01119 for(i = 0; i < rt->nb_rtsp_streams; i++) {
01120 rtsp_st = rt->rtsp_streams[i];
01121 if (id >= rtsp_st->interleaved_min &&
01122 id <= rtsp_st->interleaved_max)
01123 goto found;
01124 }
01125 goto redo;
01126 found:
01127 *prtsp_st = rtsp_st;
01128 return len;
01129 }
01130
01131 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
01132 uint8_t *buf, int buf_size)
01133 {
01134 RTSPState *rt = s->priv_data;
01135 RTSPStream *rtsp_st;
01136 fd_set rfds;
01137 int fd1, fd2, fd_max, n, i, ret;
01138 struct timeval tv;
01139
01140 for(;;) {
01141 if (url_interrupt_cb())
01142 return AVERROR(EINTR);
01143 FD_ZERO(&rfds);
01144 fd_max = -1;
01145 for(i = 0; i < rt->nb_rtsp_streams; i++) {
01146 rtsp_st = rt->rtsp_streams[i];
01147
01148 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
01149 if (fd1 > fd_max)
01150 fd_max = fd1;
01151 FD_SET(fd1, &rfds);
01152 }
01153 tv.tv_sec = 0;
01154 tv.tv_usec = 100 * 1000;
01155 n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
01156 if (n > 0) {
01157 for(i = 0; i < rt->nb_rtsp_streams; i++) {
01158 rtsp_st = rt->rtsp_streams[i];
01159 rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
01160 if (FD_ISSET(fd1, &rfds)) {
01161 ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
01162 if (ret > 0) {
01163 *prtsp_st = rtsp_st;
01164 return ret;
01165 }
01166 }
01167 }
01168 }
01169 }
01170 }
01171
01172 static int rtsp_read_packet(AVFormatContext *s,
01173 AVPacket *pkt)
01174 {
01175 RTSPState *rt = s->priv_data;
01176 RTSPStream *rtsp_st;
01177 int ret, len;
01178 uint8_t buf[RTP_MAX_PACKET_LENGTH];
01179
01180
01181 if (rt->cur_rtp) {
01182 ret = rtp_parse_packet(rt->cur_rtp, pkt, NULL, 0);
01183 if (ret == 0) {
01184 rt->cur_rtp = NULL;
01185 return 0;
01186 } else if (ret == 1) {
01187 return 0;
01188 } else {
01189 rt->cur_rtp = NULL;
01190 }
01191 }
01192
01193
01194 redo:
01195 switch(rt->protocol) {
01196 default:
01197 case RTSP_PROTOCOL_RTP_TCP:
01198 len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
01199 break;
01200 case RTSP_PROTOCOL_RTP_UDP:
01201 case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
01202 len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
01203 if (len >=0 && rtsp_st->rtp_ctx)
01204 rtp_check_and_send_back_rr(rtsp_st->rtp_ctx, len);
01205 break;
01206 }
01207 if (len < 0)
01208 return len;
01209 ret = rtp_parse_packet(rtsp_st->rtp_ctx, pkt, buf, len);
01210 if (ret < 0)
01211 goto redo;
01212 if (ret == 1) {
01213
01214 rt->cur_rtp = rtsp_st->rtp_ctx;
01215 }
01216 return 0;
01217 }
01218
01219 static int rtsp_read_play(AVFormatContext *s)
01220 {
01221 RTSPState *rt = s->priv_data;
01222 RTSPHeader reply1, *reply = &reply1;
01223 char cmd[1024];
01224
01225 av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
01226
01227 if (rt->state == RTSP_STATE_PAUSED) {
01228 snprintf(cmd, sizeof(cmd),
01229 "PLAY %s RTSP/1.0\r\n",
01230 s->filename);
01231 } else {
01232 snprintf(cmd, sizeof(cmd),
01233 "PLAY %s RTSP/1.0\r\n"
01234 "Range: npt=%0.3f-\r\n",
01235 s->filename,
01236 (double)rt->seek_timestamp / AV_TIME_BASE);
01237 }
01238 rtsp_send_cmd(s, cmd, reply, NULL);
01239 if (reply->status_code != RTSP_STATUS_OK) {
01240 return -1;
01241 } else {
01242 rt->state = RTSP_STATE_PLAYING;
01243 return 0;
01244 }
01245 }
01246
01247
01248 static int rtsp_read_pause(AVFormatContext *s)
01249 {
01250 RTSPState *rt = s->priv_data;
01251 RTSPHeader reply1, *reply = &reply1;
01252 char cmd[1024];
01253
01254 rt = s->priv_data;
01255
01256 if (rt->state != RTSP_STATE_PLAYING)
01257 return 0;
01258
01259 snprintf(cmd, sizeof(cmd),
01260 "PAUSE %s RTSP/1.0\r\n",
01261 s->filename);
01262 rtsp_send_cmd(s, cmd, reply, NULL);
01263 if (reply->status_code != RTSP_STATUS_OK) {
01264 return -1;
01265 } else {
01266 rt->state = RTSP_STATE_PAUSED;
01267 return 0;
01268 }
01269 }
01270
01271 static int rtsp_read_seek(AVFormatContext *s, int stream_index,
01272 int64_t timestamp, int flags)
01273 {
01274 RTSPState *rt = s->priv_data;
01275
01276 rt->seek_timestamp = av_rescale_q(timestamp, s->streams[stream_index]->time_base, AV_TIME_BASE_Q);
01277 switch(rt->state) {
01278 default:
01279 case RTSP_STATE_IDLE:
01280 break;
01281 case RTSP_STATE_PLAYING:
01282 if (rtsp_read_play(s) != 0)
01283 return -1;
01284 break;
01285 case RTSP_STATE_PAUSED:
01286 rt->state = RTSP_STATE_IDLE;
01287 break;
01288 }
01289 return 0;
01290 }
01291
01292 static int rtsp_read_close(AVFormatContext *s)
01293 {
01294 RTSPState *rt = s->priv_data;
01295 RTSPHeader reply1, *reply = &reply1;
01296 char cmd[1024];
01297
01298 #if 0
01299
01300 if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
01301 url_fclose(&rt->rtsp_gb);
01302 }
01303 #endif
01304 snprintf(cmd, sizeof(cmd),
01305 "TEARDOWN %s RTSP/1.0\r\n",
01306 s->filename);
01307 rtsp_send_cmd(s, cmd, reply, NULL);
01308
01309 rtsp_close_streams(rt);
01310 url_close(rt->rtsp_hd);
01311 return 0;
01312 }
01313
01314 #ifdef CONFIG_RTSP_DEMUXER
01315 AVInputFormat rtsp_demuxer = {
01316 "rtsp",
01317 "RTSP input format",
01318 sizeof(RTSPState),
01319 rtsp_probe,
01320 rtsp_read_header,
01321 rtsp_read_packet,
01322 rtsp_read_close,
01323 rtsp_read_seek,
01324 .flags = AVFMT_NOFILE,
01325 .read_play = rtsp_read_play,
01326 .read_pause = rtsp_read_pause,
01327 };
01328 #endif
01329
01330 static int sdp_probe(AVProbeData *p1)
01331 {
01332 const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
01333
01334
01335 while (p < p_end && *p != '\0') {
01336 if (p + sizeof("c=IN IP4") - 1 < p_end && av_strstart(p, "c=IN IP4", NULL))
01337 return AVPROBE_SCORE_MAX / 2;
01338
01339 while(p < p_end - 1 && *p != '\n') p++;
01340 if (++p >= p_end)
01341 break;
01342 if (*p == '\r')
01343 p++;
01344 }
01345 return 0;
01346 }
01347
01348 #define SDP_MAX_SIZE 8192
01349
01350 static int sdp_read_header(AVFormatContext *s,
01351 AVFormatParameters *ap)
01352 {
01353 RTSPState *rt = s->priv_data;
01354 RTSPStream *rtsp_st;
01355 int size, i, err;
01356 char *content;
01357 char url[1024];
01358 AVStream *st;
01359
01360
01361
01362 content = av_malloc(SDP_MAX_SIZE);
01363 size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1);
01364 if (size <= 0) {
01365 av_free(content);
01366 return AVERROR_INVALIDDATA;
01367 }
01368 content[size] ='\0';
01369
01370 sdp_parse(s, content);
01371 av_free(content);
01372
01373
01374 for(i=0;i<rt->nb_rtsp_streams;i++) {
01375 rtsp_st = rt->rtsp_streams[i];
01376
01377 snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
01378 inet_ntoa(rtsp_st->sdp_ip),
01379 rtsp_st->sdp_port,
01380 rtsp_st->sdp_ttl);
01381 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
01382 err = AVERROR_INVALIDDATA;
01383 goto fail;
01384 }
01385
01386 st = NULL;
01387 if (rtsp_st->stream_index >= 0)
01388 st = s->streams[rtsp_st->stream_index];
01389 if (!st)
01390 s->ctx_flags |= AVFMTCTX_NOHEADER;
01391 rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
01392 if (!rtsp_st->rtp_ctx) {
01393 err = AVERROR(ENOMEM);
01394 goto fail;
01395 } else {
01396 if(rtsp_st->dynamic_handler) {
01397 rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
01398 rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
01399 }
01400 }
01401 }
01402 return 0;
01403 fail:
01404 rtsp_close_streams(rt);
01405 return err;
01406 }
01407
01408 static int sdp_read_packet(AVFormatContext *s,
01409 AVPacket *pkt)
01410 {
01411 return rtsp_read_packet(s, pkt);
01412 }
01413
01414 static int sdp_read_close(AVFormatContext *s)
01415 {
01416 RTSPState *rt = s->priv_data;
01417 rtsp_close_streams(rt);
01418 return 0;
01419 }
01420
01421 #ifdef CONFIG_SDP_DEMUXER
01422 AVInputFormat sdp_demuxer = {
01423 "sdp",
01424 "SDP",
01425 sizeof(RTSPState),
01426 sdp_probe,
01427 sdp_read_header,
01428 sdp_read_packet,
01429 sdp_read_close,
01430 };
01431 #endif
01432
01433 #ifdef CONFIG_REDIR_DEMUXER
01434
01435 static int redir_probe(AVProbeData *pd)
01436 {
01437 const char *p;
01438 p = pd->buf;
01439 while (redir_isspace(*p))
01440 p++;
01441 if (av_strstart(p, "http://", NULL) ||
01442 av_strstart(p, "rtsp://", NULL))
01443 return AVPROBE_SCORE_MAX;
01444 return 0;
01445 }
01446
01447 static int redir_read_header(AVFormatContext *s, AVFormatParameters *ap)
01448 {
01449 char buf[4096], *q;
01450 int c;
01451 AVFormatContext *ic = NULL;
01452 ByteIOContext *f = s->pb;
01453
01454
01455 c = url_fgetc(f);
01456 while (c != URL_EOF) {
01457
01458 for(;;) {
01459 if (!redir_isspace(c))
01460 break;
01461 c = url_fgetc(f);
01462 }
01463 if (c == URL_EOF)
01464 break;
01465
01466 q = buf;
01467 for(;;) {
01468 if (c == URL_EOF || redir_isspace(c))
01469 break;
01470 if ((q - buf) < sizeof(buf) - 1)
01471 *q++ = c;
01472 c = url_fgetc(f);
01473 }
01474 *q = '\0';
01475
01476
01477 if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
01478 break;
01479 }
01480 if (!ic)
01481 return AVERROR(EIO);
01482
01483 *s = *ic;
01484 url_fclose(f);
01485
01486 return 0;
01487 }
01488
01489 AVInputFormat redir_demuxer = {
01490 "redir",
01491 "Redirector format",
01492 0,
01493 redir_probe,
01494 redir_read_header,
01495 NULL,
01496 NULL,
01497 };
01498 #endif