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