OLD | NEW |
1 /* | 1 /* |
2 * RTSP/SDP client | 2 * RTSP/SDP client |
3 * Copyright (c) 2002 Fabrice Bellard | 3 * Copyright (c) 2002 Fabrice Bellard |
4 * | 4 * |
5 * This file is part of FFmpeg. | 5 * This file is part of FFmpeg. |
6 * | 6 * |
7 * FFmpeg is free software; you can redistribute it and/or | 7 * FFmpeg is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Lesser General Public | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2.1 of the License, or (at your option) any later version. | 10 * version 2.1 of the License, or (at your option) any later version. |
11 * | 11 * |
12 * FFmpeg is distributed in the hope that it will be useful, | 12 * FFmpeg is distributed in the hope that it will be useful, |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Lesser General Public License for more details. | 15 * Lesser General Public License for more details. |
16 * | 16 * |
17 * You should have received a copy of the GNU Lesser General Public | 17 * You should have received a copy of the GNU Lesser General Public |
18 * License along with FFmpeg; if not, write to the Free Software | 18 * License along with FFmpeg; if not, write to the Free Software |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 */ | 20 */ |
21 | 21 |
22 /* needed by inet_aton() */ | |
23 #define _SVID_SOURCE | |
24 | |
25 #include "libavutil/base64.h" | 22 #include "libavutil/base64.h" |
26 #include "libavutil/avstring.h" | 23 #include "libavutil/avstring.h" |
27 #include "libavutil/intreadwrite.h" | 24 #include "libavutil/intreadwrite.h" |
28 #include "avformat.h" | 25 #include "avformat.h" |
29 | 26 |
30 #include <sys/time.h> | 27 #include <sys/time.h> |
31 #if HAVE_SYS_SELECT_H | 28 #if HAVE_SYS_SELECT_H |
32 #include <sys/select.h> | 29 #include <sys/select.h> |
33 #endif | 30 #endif |
34 #include <strings.h> | 31 #include <strings.h> |
35 #include "network.h" | 32 #include "network.h" |
36 #include "rtsp.h" | 33 #include "rtsp.h" |
37 | 34 |
38 #include "rtpdec.h" | 35 #include "rtpdec.h" |
39 #include "rdt.h" | 36 #include "rdt.h" |
40 #include "rtp_asf.h" | 37 #include "rtpdec_asf.h" |
41 #include "rtp_vorbis.h" | 38 #include "rtpdec_vorbis.h" |
42 | 39 |
43 //#define DEBUG | 40 //#define DEBUG |
44 //#define DEBUG_RTP_TCP | 41 //#define DEBUG_RTP_TCP |
45 | 42 |
46 #if LIBAVFORMAT_VERSION_INT < (53 << 16) | 43 #if LIBAVFORMAT_VERSION_INT < (53 << 16) |
47 int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP); | 44 int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP); |
48 #endif | 45 #endif |
49 | 46 |
50 #define SPACE_CHARS " \t\r\n" | 47 #define SPACE_CHARS " \t\r\n" |
51 /* we use memchr() instead of strchr() here because strchr() will return | 48 /* we use memchr() instead of strchr() here because strchr() will return |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 /* We are in a standard case | 121 /* We are in a standard case |
125 * (from http://www.iana.org/assignments/rtp-parameters). */ | 122 * (from http://www.iana.org/assignments/rtp-parameters). */ |
126 /* search into AVRtpPayloadTypes[] */ | 123 /* search into AVRtpPayloadTypes[] */ |
127 codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type); | 124 codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type); |
128 } | 125 } |
129 | 126 |
130 c = avcodec_find_decoder(codec->codec_id); | 127 c = avcodec_find_decoder(codec->codec_id); |
131 if (c && c->name) | 128 if (c && c->name) |
132 c_name = c->name; | 129 c_name = c->name; |
133 else | 130 else |
134 c_name = (char *) NULL; | 131 c_name = "(null)"; |
135 | 132 |
136 if (c_name) { | 133 get_word_sep(buf, sizeof(buf), "/", &p); |
137 get_word_sep(buf, sizeof(buf), "/", &p); | 134 i = atoi(buf); |
138 i = atoi(buf); | 135 switch (codec->codec_type) { |
139 switch (codec->codec_type) { | 136 case CODEC_TYPE_AUDIO: |
140 case CODEC_TYPE_AUDIO: | 137 av_log(s, AV_LOG_DEBUG, "audio codec set to: %s\n", c_name); |
141 av_log(s, AV_LOG_DEBUG, "audio codec set to: %s\n", c_name); | 138 codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE; |
142 codec->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE; | 139 codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS; |
143 codec->channels = RTSP_DEFAULT_NB_AUDIO_CHANNELS; | 140 if (i > 0) { |
144 if (i > 0) { | 141 codec->sample_rate = i; |
145 codec->sample_rate = i; | 142 get_word_sep(buf, sizeof(buf), "/", &p); |
146 get_word_sep(buf, sizeof(buf), "/", &p); | 143 i = atoi(buf); |
147 i = atoi(buf); | 144 if (i > 0) |
148 if (i > 0) | 145 codec->channels = i; |
149 codec->channels = i; | 146 // TODO: there is a bug here; if it is a mono stream, and |
150 // TODO: there is a bug here; if it is a mono stream, and | 147 // less than 22000Hz, faad upconverts to stereo and twice |
151 // less than 22000Hz, faad upconverts to stereo and twice | 148 // the frequency. No problem, but the sample rate is being |
152 // the frequency. No problem, but the sample rate is being | 149 // set here by the sdp line. Patch on its way. (rdm) |
153 // set here by the sdp line. Patch on its way. (rdm) | |
154 } | |
155 av_log(s, AV_LOG_DEBUG, "audio samplerate set to: %i\n", | |
156 codec->sample_rate); | |
157 av_log(s, AV_LOG_DEBUG, "audio channels set to: %i\n", | |
158 codec->channels); | |
159 break; | |
160 case CODEC_TYPE_VIDEO: | |
161 av_log(s, AV_LOG_DEBUG, "video codec set to: %s\n", c_name); | |
162 break; | |
163 default: | |
164 break; | |
165 } | 150 } |
166 return 0; | 151 av_log(s, AV_LOG_DEBUG, "audio samplerate set to: %i\n", |
| 152 codec->sample_rate); |
| 153 av_log(s, AV_LOG_DEBUG, "audio channels set to: %i\n", |
| 154 codec->channels); |
| 155 break; |
| 156 case CODEC_TYPE_VIDEO: |
| 157 av_log(s, AV_LOG_DEBUG, "video codec set to: %s\n", c_name); |
| 158 break; |
| 159 default: |
| 160 break; |
167 } | 161 } |
168 | 162 return 0; |
169 return -1; | |
170 } | 163 } |
171 | 164 |
172 /* return the length and optionally the data */ | 165 /* return the length and optionally the data */ |
173 static int hex_to_data(uint8_t *data, const char *p) | 166 static int hex_to_data(uint8_t *data, const char *p) |
174 { | 167 { |
175 int c, len, v; | 168 int c, len, v; |
176 | 169 |
177 len = 0; | 170 len = 0; |
178 v = 1; | 171 v = 1; |
179 for (;;) { | 172 for (;;) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 { "StreamType", ATTR_NAME_TYPE_INT, | 240 { "StreamType", ATTR_NAME_TYPE_INT, |
248 offsetof(RTPPayloadData, streamtype) }, | 241 offsetof(RTPPayloadData, streamtype) }, |
249 { "mode", ATTR_NAME_TYPE_STR, | 242 { "mode", ATTR_NAME_TYPE_STR, |
250 offsetof(RTPPayloadData, mode) }, | 243 offsetof(RTPPayloadData, mode) }, |
251 { NULL, -1, -1 }, | 244 { NULL, -1, -1 }, |
252 }; | 245 }; |
253 | 246 |
254 /* parse the attribute line from the fmtp a line of an sdp resonse. This | 247 /* parse the attribute line from the fmtp a line of an sdp resonse. This |
255 * is broken out as a function because it is used in rtp_h264.c, which is | 248 * is broken out as a function because it is used in rtp_h264.c, which is |
256 * forthcoming. */ | 249 * forthcoming. */ |
257 int rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, | 250 int ff_rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, |
258 char *value, int value_size) | 251 char *value, int value_size) |
259 { | 252 { |
260 skip_spaces(p); | 253 skip_spaces(p); |
261 if (**p) { | 254 if (**p) { |
262 get_word_sep(attr, attr_size, "=", p); | 255 get_word_sep(attr, attr_size, "=", p); |
263 if (**p == '=') | 256 if (**p == '=') |
264 (*p)++; | 257 (*p)++; |
265 get_word_sep(value, value_size, ";", p); | 258 get_word_sep(value, value_size, ";", p); |
266 if (**p == ';') | 259 if (**p == ';') |
267 (*p)++; | 260 (*p)++; |
268 return 1; | 261 return 1; |
269 } | 262 } |
270 return 0; | 263 return 0; |
271 } | 264 } |
272 | 265 |
273 /* parse a SDP line and save stream attributes */ | 266 /* parse a SDP line and save stream attributes */ |
274 static void sdp_parse_fmtp(AVStream *st, const char *p) | 267 static void sdp_parse_fmtp(AVStream *st, const char *p) |
275 { | 268 { |
276 char attr[256]; | 269 char attr[256]; |
277 /* Vorbis setup headers can be up to 12KB and are sent base64 | 270 /* Vorbis setup headers can be up to 12KB and are sent base64 |
278 * encoded, giving a 12KB * (4/3) = 16KB FMTP line. */ | 271 * encoded, giving a 12KB * (4/3) = 16KB FMTP line. */ |
279 char value[16384]; | 272 char value[16384]; |
280 int i; | 273 int i; |
281 RTSPStream *rtsp_st = st->priv_data; | 274 RTSPStream *rtsp_st = st->priv_data; |
282 AVCodecContext *codec = st->codec; | 275 AVCodecContext *codec = st->codec; |
283 RTPPayloadData *rtp_payload_data = &rtsp_st->rtp_payload_data; | 276 RTPPayloadData *rtp_payload_data = &rtsp_st->rtp_payload_data; |
284 | 277 |
285 /* loop on each attribute */ | 278 /* loop on each attribute */ |
286 while (rtsp_next_attr_and_value(&p, attr, sizeof(attr), | 279 while (ff_rtsp_next_attr_and_value(&p, attr, sizeof(attr), |
287 value, sizeof(value))) { | 280 value, sizeof(value))) { |
288 /* grab the codec extra_data from the config parameter of the fmtp | 281 /* grab the codec extra_data from the config parameter of the fmtp |
289 * line */ | 282 * line */ |
290 sdp_parse_fmtp_config(codec, rtsp_st->dynamic_protocol_context, | 283 sdp_parse_fmtp_config(codec, rtsp_st->dynamic_protocol_context, |
291 attr, value); | 284 attr, value); |
292 /* Looking for a known attribute */ | 285 /* Looking for a known attribute */ |
293 for (i = 0; attr_names[i].str; ++i) { | 286 for (i = 0; attr_names[i].str; ++i) { |
294 if (!strcasecmp(attr, attr_names[i].str)) { | 287 if (!strcasecmp(attr, attr_names[i].str)) { |
295 if (attr_names[i].type == ATTR_NAME_TYPE_INT) { | 288 if (attr_names[i].type == ATTR_NAME_TYPE_INT) { |
296 *(int *)((char *)rtp_payload_data + | 289 *(int *)((char *)rtp_payload_data + |
297 attr_names[i].offset) = atoi(value); | 290 attr_names[i].offset) = atoi(value); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 return; | 349 return; |
357 switch (letter) { | 350 switch (letter) { |
358 case 'c': | 351 case 'c': |
359 get_word(buf1, sizeof(buf1), &p); | 352 get_word(buf1, sizeof(buf1), &p); |
360 if (strcmp(buf1, "IN") != 0) | 353 if (strcmp(buf1, "IN") != 0) |
361 return; | 354 return; |
362 get_word(buf1, sizeof(buf1), &p); | 355 get_word(buf1, sizeof(buf1), &p); |
363 if (strcmp(buf1, "IP4") != 0) | 356 if (strcmp(buf1, "IP4") != 0) |
364 return; | 357 return; |
365 get_word_sep(buf1, sizeof(buf1), "/", &p); | 358 get_word_sep(buf1, sizeof(buf1), "/", &p); |
366 if (inet_aton(buf1, &sdp_ip) == 0) | 359 if (ff_inet_aton(buf1, &sdp_ip) == 0) |
367 return; | 360 return; |
368 ttl = 16; | 361 ttl = 16; |
369 if (*p == '/') { | 362 if (*p == '/') { |
370 p++; | 363 p++; |
371 get_word_sep(buf1, sizeof(buf1), "/", &p); | 364 get_word_sep(buf1, sizeof(buf1), "/", &p); |
372 ttl = atoi(buf1); | 365 ttl = atoi(buf1); |
373 } | 366 } |
374 if (s->nb_streams == 0) { | 367 if (s->nb_streams == 0) { |
375 s1->default_ip = sdp_ip; | 368 s1->default_ip = sdp_ip; |
376 s1->default_ttl = ttl; | 369 s1->default_ttl = ttl; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 if (!strncmp(p, "rtsp://", 7)) | 439 if (!strncmp(p, "rtsp://", 7)) |
447 av_strlcpy(rt->control_uri, p, | 440 av_strlcpy(rt->control_uri, p, |
448 sizeof(rt->control_uri)); | 441 sizeof(rt->control_uri)); |
449 } else { | 442 } else { |
450 char proto[32]; | 443 char proto[32]; |
451 /* get the control url */ | 444 /* get the control url */ |
452 st = s->streams[s->nb_streams - 1]; | 445 st = s->streams[s->nb_streams - 1]; |
453 rtsp_st = st->priv_data; | 446 rtsp_st = st->priv_data; |
454 | 447 |
455 /* XXX: may need to add full url resolution */ | 448 /* XXX: may need to add full url resolution */ |
456 url_split(proto, sizeof(proto), NULL, 0, NULL, 0, | 449 ff_url_split(proto, sizeof(proto), NULL, 0, NULL, 0, |
457 NULL, NULL, 0, p); | 450 NULL, NULL, 0, p); |
458 if (proto[0] == '\0') { | 451 if (proto[0] == '\0') { |
459 /* relative control URL */ | 452 /* relative control URL */ |
460 if (rtsp_st->control_url[strlen(rtsp_st->control_url)-1]!='/') | 453 if (rtsp_st->control_url[strlen(rtsp_st->control_url)-1]!='/') |
461 av_strlcat(rtsp_st->control_url, "/", | 454 av_strlcat(rtsp_st->control_url, "/", |
462 sizeof(rtsp_st->control_url)); | 455 sizeof(rtsp_st->control_url)); |
463 av_strlcat(rtsp_st->control_url, p, | 456 av_strlcat(rtsp_st->control_url, p, |
464 sizeof(rtsp_st->control_url)); | 457 sizeof(rtsp_st->control_url)); |
465 } else | 458 } else |
466 av_strlcpy(rtsp_st->control_url, p, | 459 av_strlcpy(rtsp_st->control_url, p, |
467 sizeof(rtsp_st->control_url)); | 460 sizeof(rtsp_st->control_url)); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 next_line: | 562 next_line: |
570 while (*p != '\n' && *p != '\0') | 563 while (*p != '\n' && *p != '\0') |
571 p++; | 564 p++; |
572 if (*p == '\n') | 565 if (*p == '\n') |
573 p++; | 566 p++; |
574 } | 567 } |
575 return 0; | 568 return 0; |
576 } | 569 } |
577 | 570 |
578 /* close and free RTSP streams */ | 571 /* close and free RTSP streams */ |
579 static void rtsp_close_streams(RTSPState *rt) | 572 void ff_rtsp_close_streams(AVFormatContext *s) |
580 { | 573 { |
| 574 RTSPState *rt = s->priv_data; |
581 int i; | 575 int i; |
582 RTSPStream *rtsp_st; | 576 RTSPStream *rtsp_st; |
583 | 577 |
584 for (i = 0; i < rt->nb_rtsp_streams; i++) { | 578 for (i = 0; i < rt->nb_rtsp_streams; i++) { |
585 rtsp_st = rt->rtsp_streams[i]; | 579 rtsp_st = rt->rtsp_streams[i]; |
586 if (rtsp_st) { | 580 if (rtsp_st) { |
587 if (rtsp_st->transport_priv) { | 581 if (rtsp_st->transport_priv) { |
588 if (rt->transport == RTSP_TRANSPORT_RDT) | 582 if (s->oformat) { |
| 583 AVFormatContext *rtpctx = rtsp_st->transport_priv; |
| 584 av_write_trailer(rtpctx); |
| 585 url_fclose(rtpctx->pb); |
| 586 av_metadata_free(&rtpctx->streams[0]->metadata); |
| 587 av_metadata_free(&rtpctx->metadata); |
| 588 av_free(rtpctx->streams[0]); |
| 589 av_free(rtpctx); |
| 590 } else if (rt->transport == RTSP_TRANSPORT_RDT) |
589 ff_rdt_parse_close(rtsp_st->transport_priv); | 591 ff_rdt_parse_close(rtsp_st->transport_priv); |
590 else | 592 else |
591 rtp_parse_close(rtsp_st->transport_priv); | 593 rtp_parse_close(rtsp_st->transport_priv); |
592 } | 594 } |
593 if (rtsp_st->rtp_handle) | 595 if (rtsp_st->rtp_handle) |
594 url_close(rtsp_st->rtp_handle); | 596 url_close(rtsp_st->rtp_handle); |
595 if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) | 597 if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) |
596 rtsp_st->dynamic_handler->close( | 598 rtsp_st->dynamic_handler->close( |
597 rtsp_st->dynamic_protocol_context); | 599 rtsp_st->dynamic_protocol_context); |
598 } | 600 } |
599 } | 601 } |
600 av_free(rt->rtsp_streams); | 602 av_free(rt->rtsp_streams); |
601 if (rt->asf_ctx) { | 603 if (rt->asf_ctx) { |
602 av_close_input_stream (rt->asf_ctx); | 604 av_close_input_stream (rt->asf_ctx); |
603 rt->asf_ctx = NULL; | 605 rt->asf_ctx = NULL; |
604 } | 606 } |
605 av_freep(&rt->auth_b64); | 607 av_freep(&rt->auth_b64); |
606 } | 608 } |
607 | 609 |
| 610 static void *rtsp_rtp_mux_open(AVFormatContext *s, AVStream *st, URLContext *han
dle) { |
| 611 AVFormatContext *rtpctx; |
| 612 int ret; |
| 613 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); |
| 614 |
| 615 if (!rtp_format) |
| 616 return NULL; |
| 617 |
| 618 /* Allocate an AVFormatContext for each output stream */ |
| 619 rtpctx = avformat_alloc_context(); |
| 620 if (!rtpctx) |
| 621 return NULL; |
| 622 |
| 623 rtpctx->oformat = rtp_format; |
| 624 if (!av_new_stream(rtpctx, 0)) { |
| 625 av_free(rtpctx); |
| 626 return NULL; |
| 627 } |
| 628 /* Copy the max delay setting; the rtp muxer reads this. */ |
| 629 rtpctx->max_delay = s->max_delay; |
| 630 /* Copy other stream parameters. */ |
| 631 rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; |
| 632 |
| 633 /* Remove the local codec, link to the original codec |
| 634 * context instead, to give the rtp muxer access to |
| 635 * codec parameters. */ |
| 636 av_free(rtpctx->streams[0]->codec); |
| 637 rtpctx->streams[0]->codec = st->codec; |
| 638 |
| 639 url_fdopen(&rtpctx->pb, handle); |
| 640 ret = av_write_header(rtpctx); |
| 641 |
| 642 if (ret) { |
| 643 url_fclose(rtpctx->pb); |
| 644 av_free(rtpctx->streams[0]); |
| 645 av_free(rtpctx); |
| 646 return NULL; |
| 647 } |
| 648 |
| 649 /* Copy the RTP AVStream timebase back to the original AVStream */ |
| 650 st->time_base = rtpctx->streams[0]->time_base; |
| 651 return rtpctx; |
| 652 } |
| 653 |
608 static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) | 654 static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) |
609 { | 655 { |
610 RTSPState *rt = s->priv_data; | 656 RTSPState *rt = s->priv_data; |
611 AVStream *st = NULL; | 657 AVStream *st = NULL; |
612 | 658 |
613 /* open the RTP context */ | 659 /* open the RTP context */ |
614 if (rtsp_st->stream_index >= 0) | 660 if (rtsp_st->stream_index >= 0) |
615 st = s->streams[rtsp_st->stream_index]; | 661 st = s->streams[rtsp_st->stream_index]; |
616 if (!st) | 662 if (!st) |
617 s->ctx_flags |= AVFMTCTX_NOHEADER; | 663 s->ctx_flags |= AVFMTCTX_NOHEADER; |
618 | 664 |
619 if (rt->transport == RTSP_TRANSPORT_RDT) | 665 if (s->oformat) { |
| 666 rtsp_st->transport_priv = rtsp_rtp_mux_open(s, st, rtsp_st->rtp_handle); |
| 667 /* Ownage of rtp_handle is passed to the rtp mux context */ |
| 668 rtsp_st->rtp_handle = NULL; |
| 669 } else if (rt->transport == RTSP_TRANSPORT_RDT) |
620 rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, | 670 rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, |
621 rtsp_st->dynamic_protocol_context, | 671 rtsp_st->dynamic_protocol_context, |
622 rtsp_st->dynamic_handler); | 672 rtsp_st->dynamic_handler); |
623 else | 673 else |
624 rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle, | 674 rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle, |
625 rtsp_st->sdp_payload_type, | 675 rtsp_st->sdp_payload_type, |
626 &rtsp_st->rtp_payload_data); | 676 &rtsp_st->rtp_payload_data); |
627 | 677 |
628 if (!rtsp_st->transport_priv) { | 678 if (!rtsp_st->transport_priv) { |
629 return AVERROR(ENOMEM); | 679 return AVERROR(ENOMEM); |
630 } else if (rt->transport != RTSP_TRANSPORT_RDT) { | 680 } else if (rt->transport != RTSP_TRANSPORT_RDT) { |
631 if (rtsp_st->dynamic_handler) { | 681 if (rtsp_st->dynamic_handler) { |
632 rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, | 682 rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, |
633 rtsp_st->dynamic_protocol_context, | 683 rtsp_st->dynamic_protocol_context, |
634 rtsp_st->dynamic_handler); | 684 rtsp_st->dynamic_handler); |
635 } | 685 } |
636 } | 686 } |
637 | 687 |
638 return 0; | 688 return 0; |
639 } | 689 } |
640 | 690 |
641 #if CONFIG_RTSP_DEMUXER | 691 #if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER |
642 static int rtsp_probe(AVProbeData *p) | 692 static int rtsp_probe(AVProbeData *p) |
643 { | 693 { |
644 if (av_strstart(p->filename, "rtsp:", NULL)) | 694 if (av_strstart(p->filename, "rtsp:", NULL)) |
645 return AVPROBE_SCORE_MAX; | 695 return AVPROBE_SCORE_MAX; |
646 return 0; | 696 return 0; |
647 } | 697 } |
648 | 698 |
649 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) | 699 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) |
650 { | 700 { |
651 const char *p; | 701 const char *p; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
743 if (*p == '=') { | 793 if (*p == '=') { |
744 p++; | 794 p++; |
745 th->ttl = strtol(p, (char **)&p, 10); | 795 th->ttl = strtol(p, (char **)&p, 10); |
746 } | 796 } |
747 } else if (!strcmp(parameter, "destination")) { | 797 } else if (!strcmp(parameter, "destination")) { |
748 struct in_addr ipaddr; | 798 struct in_addr ipaddr; |
749 | 799 |
750 if (*p == '=') { | 800 if (*p == '=') { |
751 p++; | 801 p++; |
752 get_word_sep(buf, sizeof(buf), ";,", &p); | 802 get_word_sep(buf, sizeof(buf), ";,", &p); |
753 if (inet_aton(buf, &ipaddr)) | 803 if (ff_inet_aton(buf, &ipaddr)) |
754 th->destination = ntohl(ipaddr.s_addr); | 804 th->destination = ntohl(ipaddr.s_addr); |
755 } | 805 } |
756 } | 806 } |
757 while (*p != ';' && *p != '\0' && *p != ',') | 807 while (*p != ';' && *p != '\0' && *p != ',') |
758 p++; | 808 p++; |
759 if (*p == ';') | 809 if (*p == ';') |
760 p++; | 810 p++; |
761 } | 811 } |
762 if (*p == ',') | 812 if (*p == ',') |
763 p++; | 813 p++; |
764 | 814 |
765 reply->nb_transports++; | 815 reply->nb_transports++; |
766 } | 816 } |
767 } | 817 } |
768 | 818 |
769 void rtsp_parse_line(RTSPMessageHeader *reply, const char *buf) | 819 void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf) |
770 { | 820 { |
771 const char *p; | 821 const char *p; |
772 | 822 |
773 /* NOTE: we do case independent match for broken servers */ | 823 /* NOTE: we do case independent match for broken servers */ |
774 p = buf; | 824 p = buf; |
775 if (av_stristart(p, "Session:", &p)) { | 825 if (av_stristart(p, "Session:", &p)) { |
776 int t; | 826 int t; |
777 get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); | 827 get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); |
778 if (av_stristart(p, ";timeout=", &p) && | 828 if (av_stristart(p, ";timeout=", &p) && |
779 (t = strtol(p, NULL, 10)) > 0) { | 829 (t = strtol(p, NULL, 10)) > 0) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 len1 = len; | 871 len1 = len; |
822 if (len1 > sizeof(buf)) | 872 if (len1 > sizeof(buf)) |
823 len1 = sizeof(buf); | 873 len1 = sizeof(buf); |
824 ret = url_read_complete(rt->rtsp_hd, buf, len1); | 874 ret = url_read_complete(rt->rtsp_hd, buf, len1); |
825 if (ret != len1) | 875 if (ret != len1) |
826 return; | 876 return; |
827 len -= len1; | 877 len -= len1; |
828 } | 878 } |
829 } | 879 } |
830 | 880 |
831 /** | 881 int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, |
832 * Read a RTSP message from the server, or prepare to read data | 882 unsigned char **content_ptr, |
833 * packets if we're reading data interleaved over the TCP/RTSP | 883 int return_on_interleaved_data) |
834 * connection as well. | |
835 * | |
836 * @param s RTSP demuxer context | |
837 * @param reply pointer where the RTSP message header will be stored | |
838 * @param content_ptr pointer where the RTSP message body, if any, will | |
839 * be stored (length is in reply) | |
840 * @param return_on_interleaved_data whether the function may return if we | |
841 * encounter a data marker ('$'), which precedes data | |
842 * packets over interleaved TCP/RTSP connections. If this | |
843 * is set, this function will return 1 after encountering | |
844 * a '$'. If it is not set, the function will skip any | |
845 * data packets (if they are encountered), until a reply | |
846 * has been fully parsed. If no more data is available | |
847 * without parsing a reply, it will return an error. | |
848 * | |
849 * @returns 1 if a data packets is ready to be received, -1 on error, | |
850 * and 0 on success. | |
851 */ | |
852 static int rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, | |
853 unsigned char **content_ptr, | |
854 int return_on_interleaved_data) | |
855 { | 884 { |
856 RTSPState *rt = s->priv_data; | 885 RTSPState *rt = s->priv_data; |
857 char buf[4096], buf1[1024], *q; | 886 char buf[4096], buf1[1024], *q; |
858 unsigned char ch; | 887 unsigned char ch; |
859 const char *p; | 888 const char *p; |
860 int ret, content_length, line_count = 0; | 889 int ret, content_length, line_count = 0; |
861 unsigned char *content = NULL; | 890 unsigned char *content = NULL; |
862 | 891 |
863 memset(reply, 0, sizeof(*reply)); | 892 memset(reply, 0, sizeof(*reply)); |
864 | 893 |
(...skipping 28 matching lines...) Expand all Loading... |
893 /* test if last line */ | 922 /* test if last line */ |
894 if (buf[0] == '\0') | 923 if (buf[0] == '\0') |
895 break; | 924 break; |
896 p = buf; | 925 p = buf; |
897 if (line_count == 0) { | 926 if (line_count == 0) { |
898 /* get reply code */ | 927 /* get reply code */ |
899 get_word(buf1, sizeof(buf1), &p); | 928 get_word(buf1, sizeof(buf1), &p); |
900 get_word(buf1, sizeof(buf1), &p); | 929 get_word(buf1, sizeof(buf1), &p); |
901 reply->status_code = atoi(buf1); | 930 reply->status_code = atoi(buf1); |
902 } else { | 931 } else { |
903 rtsp_parse_line(reply, p); | 932 ff_rtsp_parse_line(reply, p); |
904 av_strlcat(rt->last_reply, p, sizeof(rt->last_reply)); | 933 av_strlcat(rt->last_reply, p, sizeof(rt->last_reply)); |
905 av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply)); | 934 av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply)); |
906 } | 935 } |
907 line_count++; | 936 line_count++; |
908 } | 937 } |
909 | 938 |
910 if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') | 939 if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') |
911 av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id)); | 940 av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id)); |
912 | 941 |
913 content_length = reply->content_length; | 942 content_length = reply->content_length; |
(...skipping 15 matching lines...) Expand all Loading... |
929 rt->state = RTSP_STATE_IDLE; | 958 rt->state = RTSP_STATE_IDLE; |
930 } else if (reply->notice >= 4400 && reply->notice < 5500) { | 959 } else if (reply->notice >= 4400 && reply->notice < 5500) { |
931 return AVERROR(EIO); /* data or server error */ | 960 return AVERROR(EIO); /* data or server error */ |
932 } else if (reply->notice == 2401 /* Ticket Expired */ || | 961 } else if (reply->notice == 2401 /* Ticket Expired */ || |
933 (reply->notice >= 5500 && reply->notice < 5600) /* end of term */ ) | 962 (reply->notice >= 5500 && reply->notice < 5600) /* end of term */ ) |
934 return AVERROR(EPERM); | 963 return AVERROR(EPERM); |
935 | 964 |
936 return 0; | 965 return 0; |
937 } | 966 } |
938 | 967 |
939 static void rtsp_send_cmd_async(AVFormatContext *s, const char *cmd) | 968 void ff_rtsp_send_cmd_with_content_async(AVFormatContext *s, |
| 969 const char *cmd, |
| 970 const unsigned char *send_content, |
| 971 int send_content_length) |
940 { | 972 { |
941 RTSPState *rt = s->priv_data; | 973 RTSPState *rt = s->priv_data; |
942 char buf[4096], buf1[1024]; | 974 char buf[4096], buf1[1024]; |
943 | 975 |
944 rt->seq++; | 976 rt->seq++; |
945 av_strlcpy(buf, cmd, sizeof(buf)); | 977 av_strlcpy(buf, cmd, sizeof(buf)); |
946 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq); | 978 snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq); |
947 av_strlcat(buf, buf1, sizeof(buf)); | 979 av_strlcat(buf, buf1, sizeof(buf)); |
948 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) { | 980 if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) { |
949 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id); | 981 snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id); |
950 av_strlcat(buf, buf1, sizeof(buf)); | 982 av_strlcat(buf, buf1, sizeof(buf)); |
951 } | 983 } |
952 if (rt->auth_b64) | 984 if (rt->auth_b64) |
953 av_strlcatf(buf, sizeof(buf), | 985 av_strlcatf(buf, sizeof(buf), |
954 "Authorization: Basic %s\r\n", | 986 "Authorization: Basic %s\r\n", |
955 rt->auth_b64); | 987 rt->auth_b64); |
| 988 if (send_content_length > 0 && send_content) |
| 989 av_strlcatf(buf, sizeof(buf), "Content-Length: %d\r\n", send_content_len
gth); |
956 av_strlcat(buf, "\r\n", sizeof(buf)); | 990 av_strlcat(buf, "\r\n", sizeof(buf)); |
957 | 991 |
958 dprintf(s, "Sending:\n%s--\n", buf); | 992 dprintf(s, "Sending:\n%s--\n", buf); |
959 | 993 |
960 url_write(rt->rtsp_hd, buf, strlen(buf)); | 994 url_write(rt->rtsp_hd, buf, strlen(buf)); |
| 995 if (send_content_length > 0 && send_content) |
| 996 url_write(rt->rtsp_hd, send_content, send_content_length); |
961 rt->last_cmd_time = av_gettime(); | 997 rt->last_cmd_time = av_gettime(); |
962 } | 998 } |
963 | 999 |
964 static void rtsp_send_cmd(AVFormatContext *s, | 1000 void ff_rtsp_send_cmd_async(AVFormatContext *s, const char *cmd) |
965 const char *cmd, RTSPMessageHeader *reply, | |
966 unsigned char **content_ptr) | |
967 { | 1001 { |
968 rtsp_send_cmd_async(s, cmd); | 1002 ff_rtsp_send_cmd_with_content_async(s, cmd, NULL, 0); |
| 1003 } |
969 | 1004 |
970 rtsp_read_reply(s, reply, content_ptr, 0); | 1005 void ff_rtsp_send_cmd(AVFormatContext *s, |
| 1006 const char *cmd, RTSPMessageHeader *reply, |
| 1007 unsigned char **content_ptr) |
| 1008 { |
| 1009 ff_rtsp_send_cmd_async(s, cmd); |
| 1010 |
| 1011 ff_rtsp_read_reply(s, reply, content_ptr, 0); |
| 1012 } |
| 1013 |
| 1014 void ff_rtsp_send_cmd_with_content(AVFormatContext *s, |
| 1015 const char *cmd, |
| 1016 RTSPMessageHeader *reply, |
| 1017 unsigned char **content_ptr, |
| 1018 const unsigned char *send_content, |
| 1019 int send_content_length) |
| 1020 { |
| 1021 ff_rtsp_send_cmd_with_content_async(s, cmd, send_content, send_content_lengt
h); |
| 1022 |
| 1023 ff_rtsp_read_reply(s, reply, content_ptr, 0); |
971 } | 1024 } |
972 | 1025 |
973 /** | 1026 /** |
974 * @returns 0 on success, <0 on error, 1 if protocol is unavailable. | 1027 * @returns 0 on success, <0 on error, 1 if protocol is unavailable. |
975 */ | 1028 */ |
976 static int make_setup_request(AVFormatContext *s, const char *host, int port, | 1029 static int make_setup_request(AVFormatContext *s, const char *host, int port, |
977 int lower_transport, const char *real_challenge) | 1030 int lower_transport, const char *real_challenge) |
978 { | 1031 { |
979 RTSPState *rt = s->priv_data; | 1032 RTSPState *rt = s->priv_data; |
980 int rtx, j, i, err, interleave = 0; | 1033 int rtx, j, i, err, interleave = 0; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 char buf[256]; | 1080 char buf[256]; |
1028 | 1081 |
1029 if (rt->server_type == RTSP_SERVER_WMS && i > 1) { | 1082 if (rt->server_type == RTSP_SERVER_WMS && i > 1) { |
1030 port = reply->transports[0].client_port_min; | 1083 port = reply->transports[0].client_port_min; |
1031 goto have_port; | 1084 goto have_port; |
1032 } | 1085 } |
1033 | 1086 |
1034 /* first try in specified port range */ | 1087 /* first try in specified port range */ |
1035 if (RTSP_RTP_PORT_MIN != 0) { | 1088 if (RTSP_RTP_PORT_MIN != 0) { |
1036 while (j <= RTSP_RTP_PORT_MAX) { | 1089 while (j <= RTSP_RTP_PORT_MAX) { |
1037 snprintf(buf, sizeof(buf), "rtp://%s?localport=%d", | 1090 ff_url_join(buf, sizeof(buf), "rtp", NULL, host, -1, |
1038 host, j); | 1091 "?localport=%d", j); |
1039 /* we will use two ports per rtp stream (rtp and rtcp) */ | 1092 /* we will use two ports per rtp stream (rtp and rtcp) */ |
1040 j += 2; | 1093 j += 2; |
1041 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) | 1094 if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) |
1042 goto rtp_opened; | 1095 goto rtp_opened; |
1043 } | 1096 } |
1044 } | 1097 } |
1045 | 1098 |
1046 #if 0 | 1099 #if 0 |
1047 /* then try on any port */ | 1100 /* then try on any port */ |
1048 if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { | 1101 if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1081 av_strlcatf(transport, sizeof(transport), | 1134 av_strlcatf(transport, sizeof(transport), |
1082 "interleaved=%d-%d", | 1135 "interleaved=%d-%d", |
1083 interleave, interleave + 1); | 1136 interleave, interleave + 1); |
1084 interleave += 2; | 1137 interleave += 2; |
1085 } | 1138 } |
1086 | 1139 |
1087 else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) { | 1140 else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) { |
1088 snprintf(transport, sizeof(transport) - 1, | 1141 snprintf(transport, sizeof(transport) - 1, |
1089 "%s/UDP;multicast", trans_pref); | 1142 "%s/UDP;multicast", trans_pref); |
1090 } | 1143 } |
1091 if (rt->server_type == RTSP_SERVER_REAL || | 1144 if (s->oformat) { |
1092 rt->server_type == RTSP_SERVER_WMS) | 1145 av_strlcat(transport, ";mode=receive", sizeof(transport)); |
| 1146 } else if (rt->server_type == RTSP_SERVER_REAL || |
| 1147 rt->server_type == RTSP_SERVER_WMS) |
1093 av_strlcat(transport, ";mode=play", sizeof(transport)); | 1148 av_strlcat(transport, ";mode=play", sizeof(transport)); |
1094 snprintf(cmd, sizeof(cmd), | 1149 snprintf(cmd, sizeof(cmd), |
1095 "SETUP %s RTSP/1.0\r\n" | 1150 "SETUP %s RTSP/1.0\r\n" |
1096 "Transport: %s\r\n", | 1151 "Transport: %s\r\n", |
1097 rtsp_st->control_url, transport); | 1152 rtsp_st->control_url, transport); |
1098 if (i == 0 && rt->server_type == RTSP_SERVER_REAL) { | 1153 if (i == 0 && rt->server_type == RTSP_SERVER_REAL) { |
1099 char real_res[41], real_csum[9]; | 1154 char real_res[41], real_csum[9]; |
1100 ff_rdt_calc_response_and_checksum(real_res, real_csum, | 1155 ff_rdt_calc_response_and_checksum(real_res, real_csum, |
1101 real_challenge); | 1156 real_challenge); |
1102 av_strlcatf(cmd, sizeof(cmd), | 1157 av_strlcatf(cmd, sizeof(cmd), |
1103 "If-Match: %s\r\n" | 1158 "If-Match: %s\r\n" |
1104 "RealChallenge2: %s, sd=%s\r\n", | 1159 "RealChallenge2: %s, sd=%s\r\n", |
1105 rt->session_id, real_res, real_csum); | 1160 rt->session_id, real_res, real_csum); |
1106 } | 1161 } |
1107 rtsp_send_cmd(s, cmd, reply, NULL); | 1162 ff_rtsp_send_cmd(s, cmd, reply, NULL); |
1108 if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { | 1163 if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { |
1109 err = 1; | 1164 err = 1; |
1110 goto fail; | 1165 goto fail; |
1111 } else if (reply->status_code != RTSP_STATUS_OK || | 1166 } else if (reply->status_code != RTSP_STATUS_OK || |
1112 reply->nb_transports != 1) { | 1167 reply->nb_transports != 1) { |
1113 err = AVERROR_INVALIDDATA; | 1168 err = AVERROR_INVALIDDATA; |
1114 goto fail; | 1169 goto fail; |
1115 } | 1170 } |
1116 | 1171 |
1117 /* XXX: same protocol for all streams is required */ | 1172 /* XXX: same protocol for all streams is required */ |
(...skipping 18 matching lines...) Expand all Loading... |
1136 switch(reply->transports[0].lower_transport) { | 1191 switch(reply->transports[0].lower_transport) { |
1137 case RTSP_LOWER_TRANSPORT_TCP: | 1192 case RTSP_LOWER_TRANSPORT_TCP: |
1138 rtsp_st->interleaved_min = reply->transports[0].interleaved_min; | 1193 rtsp_st->interleaved_min = reply->transports[0].interleaved_min; |
1139 rtsp_st->interleaved_max = reply->transports[0].interleaved_max; | 1194 rtsp_st->interleaved_max = reply->transports[0].interleaved_max; |
1140 break; | 1195 break; |
1141 | 1196 |
1142 case RTSP_LOWER_TRANSPORT_UDP: { | 1197 case RTSP_LOWER_TRANSPORT_UDP: { |
1143 char url[1024]; | 1198 char url[1024]; |
1144 | 1199 |
1145 /* XXX: also use address if specified */ | 1200 /* XXX: also use address if specified */ |
1146 snprintf(url, sizeof(url), "rtp://%s:%d", | 1201 ff_url_join(url, sizeof(url), "rtp", NULL, host, |
1147 host, reply->transports[0].server_port_min); | 1202 reply->transports[0].server_port_min, NULL); |
1148 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && | 1203 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && |
1149 rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { | 1204 rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { |
1150 err = AVERROR_INVALIDDATA; | 1205 err = AVERROR_INVALIDDATA; |
1151 goto fail; | 1206 goto fail; |
1152 } | 1207 } |
| 1208 /* Try to initialize the connection state in a |
| 1209 * potential NAT router by sending dummy packets. |
| 1210 * RTP/RTCP dummy packets are used for RDT, too. |
| 1211 */ |
| 1212 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && s->iformat) |
| 1213 rtp_send_punch_packets(rtsp_st->rtp_handle); |
1153 break; | 1214 break; |
1154 } | 1215 } |
1155 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { | 1216 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { |
1156 char url[1024]; | 1217 char url[1024]; |
1157 struct in_addr in; | 1218 struct in_addr in; |
1158 int port, ttl; | 1219 int port, ttl; |
1159 | 1220 |
1160 if (reply->transports[0].destination) { | 1221 if (reply->transports[0].destination) { |
1161 in.s_addr = htonl(reply->transports[0].destination); | 1222 in.s_addr = htonl(reply->transports[0].destination); |
1162 port = reply->transports[0].port_min; | 1223 port = reply->transports[0].port_min; |
1163 ttl = reply->transports[0].ttl; | 1224 ttl = reply->transports[0].ttl; |
1164 } else { | 1225 } else { |
1165 in = rtsp_st->sdp_ip; | 1226 in = rtsp_st->sdp_ip; |
1166 port = rtsp_st->sdp_port; | 1227 port = rtsp_st->sdp_port; |
1167 ttl = rtsp_st->sdp_ttl; | 1228 ttl = rtsp_st->sdp_ttl; |
1168 } | 1229 } |
1169 snprintf(url, sizeof(url), "rtp://%s:%d?ttl=%d", | 1230 ff_url_join(url, sizeof(url), "rtp", NULL, inet_ntoa(in), |
1170 inet_ntoa(in), port, ttl); | 1231 port, "?ttl=%d", ttl); |
1171 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { | 1232 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { |
1172 err = AVERROR_INVALIDDATA; | 1233 err = AVERROR_INVALIDDATA; |
1173 goto fail; | 1234 goto fail; |
1174 } | 1235 } |
1175 break; | 1236 break; |
1176 } | 1237 } |
1177 } | 1238 } |
1178 | 1239 |
1179 if ((err = rtsp_open_transport_ctx(s, rtsp_st))) | 1240 if ((err = rtsp_open_transport_ctx(s, rtsp_st))) |
1180 goto fail; | 1241 goto fail; |
(...skipping 30 matching lines...) Expand all Loading... |
1211 snprintf(cmd, sizeof(cmd), | 1272 snprintf(cmd, sizeof(cmd), |
1212 "PLAY %s RTSP/1.0\r\n", | 1273 "PLAY %s RTSP/1.0\r\n", |
1213 rt->control_uri); | 1274 rt->control_uri); |
1214 } else { | 1275 } else { |
1215 snprintf(cmd, sizeof(cmd), | 1276 snprintf(cmd, sizeof(cmd), |
1216 "PLAY %s RTSP/1.0\r\n" | 1277 "PLAY %s RTSP/1.0\r\n" |
1217 "Range: npt=%0.3f-\r\n", | 1278 "Range: npt=%0.3f-\r\n", |
1218 rt->control_uri, | 1279 rt->control_uri, |
1219 (double)rt->seek_timestamp / AV_TIME_BASE); | 1280 (double)rt->seek_timestamp / AV_TIME_BASE); |
1220 } | 1281 } |
1221 rtsp_send_cmd(s, cmd, reply, NULL); | 1282 ff_rtsp_send_cmd(s, cmd, reply, NULL); |
1222 if (reply->status_code != RTSP_STATUS_OK) { | 1283 if (reply->status_code != RTSP_STATUS_OK) { |
1223 return -1; | 1284 return -1; |
1224 } | 1285 } |
1225 } | 1286 } |
1226 rt->state = RTSP_STATE_PLAYING; | 1287 rt->state = RTSP_STATE_STREAMING; |
1227 return 0; | 1288 return 0; |
1228 } | 1289 } |
1229 | 1290 |
1230 static int rtsp_read_header(AVFormatContext *s, | 1291 static int rtsp_setup_input_streams(AVFormatContext *s) |
1231 AVFormatParameters *ap) | 1292 { |
| 1293 RTSPState *rt = s->priv_data; |
| 1294 RTSPMessageHeader reply1, *reply = &reply1; |
| 1295 char cmd[1024]; |
| 1296 unsigned char *content = NULL; |
| 1297 int ret; |
| 1298 |
| 1299 /* describe the stream */ |
| 1300 snprintf(cmd, sizeof(cmd), |
| 1301 "DESCRIBE %s RTSP/1.0\r\n" |
| 1302 "Accept: application/sdp\r\n", |
| 1303 s->filename); |
| 1304 if (rt->server_type == RTSP_SERVER_REAL) { |
| 1305 /** |
| 1306 * The Require: attribute is needed for proper streaming from |
| 1307 * Realmedia servers. |
| 1308 */ |
| 1309 av_strlcat(cmd, |
| 1310 "Require: com.real.retain-entity-for-setup\r\n", |
| 1311 sizeof(cmd)); |
| 1312 } |
| 1313 ff_rtsp_send_cmd(s, cmd, reply, &content); |
| 1314 if (!content) |
| 1315 return AVERROR_INVALIDDATA; |
| 1316 if (reply->status_code != RTSP_STATUS_OK) { |
| 1317 av_freep(&content); |
| 1318 return AVERROR_INVALIDDATA; |
| 1319 } |
| 1320 |
| 1321 /* now we got the SDP description, we parse it */ |
| 1322 ret = sdp_parse(s, (const char *)content); |
| 1323 av_freep(&content); |
| 1324 if (ret < 0) |
| 1325 return AVERROR_INVALIDDATA; |
| 1326 |
| 1327 return 0; |
| 1328 } |
| 1329 |
| 1330 static int rtsp_setup_output_streams(AVFormatContext *s) |
| 1331 { |
| 1332 RTSPState *rt = s->priv_data; |
| 1333 RTSPMessageHeader reply1, *reply = &reply1; |
| 1334 char cmd[1024]; |
| 1335 int i; |
| 1336 char *sdp; |
| 1337 |
| 1338 /* Announce the stream */ |
| 1339 snprintf(cmd, sizeof(cmd), |
| 1340 "ANNOUNCE %s RTSP/1.0\r\n" |
| 1341 "Content-Type: application/sdp\r\n", |
| 1342 s->filename); |
| 1343 sdp = av_mallocz(8192); |
| 1344 if (sdp == NULL) |
| 1345 return AVERROR(ENOMEM); |
| 1346 if (avf_sdp_create(&s, 1, sdp, 8192)) { |
| 1347 av_free(sdp); |
| 1348 return AVERROR_INVALIDDATA; |
| 1349 } |
| 1350 av_log(s, AV_LOG_INFO, "SDP:\n%s\n", sdp); |
| 1351 ff_rtsp_send_cmd_with_content(s, cmd, reply, NULL, sdp, strlen(sdp)); |
| 1352 av_free(sdp); |
| 1353 if (reply->status_code != RTSP_STATUS_OK) |
| 1354 return AVERROR_INVALIDDATA; |
| 1355 |
| 1356 /* Set up the RTSPStreams for each AVStream */ |
| 1357 for (i = 0; i < s->nb_streams; i++) { |
| 1358 RTSPStream *rtsp_st; |
| 1359 AVStream *st = s->streams[i]; |
| 1360 |
| 1361 rtsp_st = av_mallocz(sizeof(RTSPStream)); |
| 1362 if (!rtsp_st) |
| 1363 return AVERROR(ENOMEM); |
| 1364 dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); |
| 1365 |
| 1366 st->priv_data = rtsp_st; |
| 1367 rtsp_st->stream_index = i; |
| 1368 |
| 1369 av_strlcpy(rtsp_st->control_url, s->filename, sizeof(rtsp_st->control_ur
l)); |
| 1370 /* Note, this must match the relative uri set in the sdp content */ |
| 1371 av_strlcatf(rtsp_st->control_url, sizeof(rtsp_st->control_url), |
| 1372 "/streamid=%d", i); |
| 1373 } |
| 1374 |
| 1375 return 0; |
| 1376 } |
| 1377 |
| 1378 int ff_rtsp_connect(AVFormatContext *s) |
1232 { | 1379 { |
1233 RTSPState *rt = s->priv_data; | 1380 RTSPState *rt = s->priv_data; |
1234 char host[1024], path[1024], tcpname[1024], cmd[2048], auth[128]; | 1381 char host[1024], path[1024], tcpname[1024], cmd[2048], auth[128]; |
1235 char *option_list, *option, *filename; | 1382 char *option_list, *option, *filename; |
1236 URLContext *rtsp_hd; | 1383 URLContext *rtsp_hd; |
1237 int port, ret, err; | 1384 int port, err; |
1238 RTSPMessageHeader reply1, *reply = &reply1; | 1385 RTSPMessageHeader reply1, *reply = &reply1; |
1239 unsigned char *content = NULL; | |
1240 int lower_transport_mask = 0; | 1386 int lower_transport_mask = 0; |
1241 char real_challenge[64]; | 1387 char real_challenge[64]; |
| 1388 |
| 1389 if (!ff_network_init()) |
| 1390 return AVERROR(EIO); |
1242 redirect: | 1391 redirect: |
1243 /* extract hostname and port */ | 1392 /* extract hostname and port */ |
1244 url_split(NULL, 0, auth, sizeof(auth), | 1393 ff_url_split(NULL, 0, auth, sizeof(auth), |
1245 host, sizeof(host), &port, path, sizeof(path), s->filename); | 1394 host, sizeof(host), &port, path, sizeof(path), s->filename); |
1246 if (*auth) { | 1395 if (*auth) { |
1247 int auth_len = strlen(auth), b64_len = ((auth_len + 2) / 3) * 4 + 1; | 1396 int auth_len = strlen(auth), b64_len = ((auth_len + 2) / 3) * 4 + 1; |
1248 | 1397 |
1249 if (!(rt->auth_b64 = av_malloc(b64_len))) | 1398 if (!(rt->auth_b64 = av_malloc(b64_len))) |
1250 return AVERROR(ENOMEM); | 1399 return AVERROR(ENOMEM); |
1251 if (!av_base64_encode(rt->auth_b64, b64_len, auth, auth_len)) { | 1400 if (!av_base64_encode(rt->auth_b64, b64_len, auth, auth_len)) { |
1252 err = AVERROR(EINVAL); | 1401 err = AVERROR(EINVAL); |
1253 goto fail; | 1402 goto fail; |
1254 } | 1403 } |
1255 } | 1404 } |
(...skipping 23 matching lines...) Expand all Loading... |
1279 filename += strlen(option); | 1428 filename += strlen(option); |
1280 if (option_list) *filename = '&'; | 1429 if (option_list) *filename = '&'; |
1281 } | 1430 } |
1282 } | 1431 } |
1283 *filename = 0; | 1432 *filename = 0; |
1284 } | 1433 } |
1285 | 1434 |
1286 if (!lower_transport_mask) | 1435 if (!lower_transport_mask) |
1287 lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1; | 1436 lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1; |
1288 | 1437 |
| 1438 if (s->oformat) { |
| 1439 /* Only UDP output is supported at the moment. */ |
| 1440 lower_transport_mask &= 1 << RTSP_LOWER_TRANSPORT_UDP; |
| 1441 if (!lower_transport_mask) { |
| 1442 av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, " |
| 1443 "only UDP is supported for output.\n"); |
| 1444 err = AVERROR(EINVAL); |
| 1445 goto fail; |
| 1446 } |
| 1447 } |
| 1448 |
1289 /* open the tcp connexion */ | 1449 /* open the tcp connexion */ |
1290 snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port); | 1450 ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL); |
1291 if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) { | 1451 if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) { |
1292 err = AVERROR(EIO); | 1452 err = AVERROR(EIO); |
1293 goto fail; | 1453 goto fail; |
1294 } | 1454 } |
1295 rt->rtsp_hd = rtsp_hd; | 1455 rt->rtsp_hd = rtsp_hd; |
1296 rt->seq = 0; | 1456 rt->seq = 0; |
1297 | 1457 |
1298 /* request options supported by the server; this also detects server | 1458 /* request options supported by the server; this also detects server |
1299 * type */ | 1459 * type */ |
1300 av_strlcpy(rt->control_uri, s->filename, | 1460 av_strlcpy(rt->control_uri, s->filename, |
(...skipping 10 matching lines...) Expand all Loading... |
1311 * don't quite understand how. Values were copied | 1471 * don't quite understand how. Values were copied |
1312 * from mplayer SVN r23589. | 1472 * from mplayer SVN r23589. |
1313 * @param CompanyID is a 16-byte ID in base64 | 1473 * @param CompanyID is a 16-byte ID in base64 |
1314 * @param ClientChallenge is a 16-byte ID in hex | 1474 * @param ClientChallenge is a 16-byte ID in hex |
1315 */ | 1475 */ |
1316 "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n" | 1476 "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n" |
1317 "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n" | 1477 "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n" |
1318 "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n" | 1478 "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n" |
1319 "GUID: 00000000-0000-0000-0000-000000000000\r\n", | 1479 "GUID: 00000000-0000-0000-0000-000000000000\r\n", |
1320 sizeof(cmd)); | 1480 sizeof(cmd)); |
1321 rtsp_send_cmd(s, cmd, reply, NULL); | 1481 ff_rtsp_send_cmd(s, cmd, reply, NULL); |
1322 if (reply->status_code != RTSP_STATUS_OK) { | 1482 if (reply->status_code != RTSP_STATUS_OK) { |
1323 err = AVERROR_INVALIDDATA; | 1483 err = AVERROR_INVALIDDATA; |
1324 goto fail; | 1484 goto fail; |
1325 } | 1485 } |
1326 | 1486 |
1327 /* detect server type if not standard-compliant RTP */ | 1487 /* detect server type if not standard-compliant RTP */ |
1328 if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { | 1488 if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { |
1329 rt->server_type = RTSP_SERVER_REAL; | 1489 rt->server_type = RTSP_SERVER_REAL; |
1330 continue; | 1490 continue; |
1331 } else if (!strncasecmp(reply->server, "WMServer/", 9)) { | 1491 } else if (!strncasecmp(reply->server, "WMServer/", 9)) { |
1332 rt->server_type = RTSP_SERVER_WMS; | 1492 rt->server_type = RTSP_SERVER_WMS; |
1333 } else if (rt->server_type == RTSP_SERVER_REAL) | 1493 } else if (rt->server_type == RTSP_SERVER_REAL) |
1334 strcpy(real_challenge, reply->real_challenge); | 1494 strcpy(real_challenge, reply->real_challenge); |
1335 break; | 1495 break; |
1336 } | 1496 } |
1337 | 1497 |
1338 /* describe the stream */ | 1498 if (s->iformat) |
1339 snprintf(cmd, sizeof(cmd), | 1499 err = rtsp_setup_input_streams(s); |
1340 "DESCRIBE %s RTSP/1.0\r\n" | 1500 else |
1341 "Accept: application/sdp\r\n", | 1501 err = rtsp_setup_output_streams(s); |
1342 s->filename); | 1502 if (err) |
1343 if (rt->server_type == RTSP_SERVER_REAL) { | |
1344 /** | |
1345 * The Require: attribute is needed for proper streaming from | |
1346 * Realmedia servers. | |
1347 */ | |
1348 av_strlcat(cmd, | |
1349 "Require: com.real.retain-entity-for-setup\r\n", | |
1350 sizeof(cmd)); | |
1351 } | |
1352 rtsp_send_cmd(s, cmd, reply, &content); | |
1353 if (!content) { | |
1354 err = AVERROR_INVALIDDATA; | |
1355 goto fail; | 1503 goto fail; |
1356 } | |
1357 if (reply->status_code != RTSP_STATUS_OK) { | |
1358 err = AVERROR_INVALIDDATA; | |
1359 goto fail; | |
1360 } | |
1361 | |
1362 /* now we got the SDP description, we parse it */ | |
1363 ret = sdp_parse(s, (const char *)content); | |
1364 av_freep(&content); | |
1365 if (ret < 0) { | |
1366 err = AVERROR_INVALIDDATA; | |
1367 goto fail; | |
1368 } | |
1369 | 1504 |
1370 do { | 1505 do { |
1371 int lower_transport = ff_log2_tab[lower_transport_mask & | 1506 int lower_transport = ff_log2_tab[lower_transport_mask & |
1372 ~(lower_transport_mask - 1)]; | 1507 ~(lower_transport_mask - 1)]; |
1373 | 1508 |
1374 err = make_setup_request(s, host, port, lower_transport, | 1509 err = make_setup_request(s, host, port, lower_transport, |
1375 rt->server_type == RTSP_SERVER_REAL ? | 1510 rt->server_type == RTSP_SERVER_REAL ? |
1376 real_challenge : NULL); | 1511 real_challenge : NULL); |
1377 if (err < 0) | 1512 if (err < 0) |
1378 goto fail; | 1513 goto fail; |
1379 lower_transport_mask &= ~(1 << lower_transport); | 1514 lower_transport_mask &= ~(1 << lower_transport); |
1380 if (lower_transport_mask == 0 && err == 1) { | 1515 if (lower_transport_mask == 0 && err == 1) { |
1381 err = AVERROR(FF_NETERROR(EPROTONOSUPPORT)); | 1516 err = AVERROR(FF_NETERROR(EPROTONOSUPPORT)); |
1382 goto fail; | 1517 goto fail; |
1383 } | 1518 } |
1384 } while (err); | 1519 } while (err); |
1385 | 1520 |
1386 rt->state = RTSP_STATE_IDLE; | 1521 rt->state = RTSP_STATE_IDLE; |
1387 rt->seek_timestamp = 0; /* default is to start stream at position zero */ | 1522 rt->seek_timestamp = 0; /* default is to start stream at position zero */ |
1388 if (ap->initial_pause) { | |
1389 /* do not start immediately */ | |
1390 } else { | |
1391 if (rtsp_read_play(s) < 0) { | |
1392 err = AVERROR_INVALIDDATA; | |
1393 goto fail; | |
1394 } | |
1395 } | |
1396 return 0; | 1523 return 0; |
1397 fail: | 1524 fail: |
1398 rtsp_close_streams(rt); | 1525 ff_rtsp_close_streams(s); |
1399 av_freep(&content); | |
1400 url_close(rt->rtsp_hd); | 1526 url_close(rt->rtsp_hd); |
1401 if (reply->status_code >=300 && reply->status_code < 400) { | 1527 if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) { |
1402 av_strlcpy(s->filename, reply->location, sizeof(s->filename)); | 1528 av_strlcpy(s->filename, reply->location, sizeof(s->filename)); |
1403 av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", | 1529 av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", |
1404 reply->status_code, | 1530 reply->status_code, |
1405 s->filename); | 1531 s->filename); |
1406 goto redirect; | 1532 goto redirect; |
1407 } | 1533 } |
| 1534 ff_network_close(); |
1408 return err; | 1535 return err; |
1409 } | 1536 } |
| 1537 #endif |
| 1538 |
| 1539 #if CONFIG_RTSP_DEMUXER |
| 1540 static int rtsp_read_header(AVFormatContext *s, |
| 1541 AVFormatParameters *ap) |
| 1542 { |
| 1543 RTSPState *rt = s->priv_data; |
| 1544 int ret; |
| 1545 |
| 1546 ret = ff_rtsp_connect(s); |
| 1547 if (ret) |
| 1548 return ret; |
| 1549 |
| 1550 if (ap->initial_pause) { |
| 1551 /* do not start immediately */ |
| 1552 } else { |
| 1553 if (rtsp_read_play(s) < 0) { |
| 1554 ff_rtsp_close_streams(s); |
| 1555 url_close(rt->rtsp_hd); |
| 1556 return AVERROR_INVALIDDATA; |
| 1557 } |
| 1558 } |
| 1559 |
| 1560 return 0; |
| 1561 } |
1410 | 1562 |
1411 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, | 1563 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, |
1412 uint8_t *buf, int buf_size) | 1564 uint8_t *buf, int buf_size) |
1413 { | 1565 { |
1414 RTSPState *rt = s->priv_data; | 1566 RTSPState *rt = s->priv_data; |
1415 RTSPStream *rtsp_st; | 1567 RTSPStream *rtsp_st; |
1416 fd_set rfds; | 1568 fd_set rfds; |
1417 int fd, fd_max, n, i, ret, tcp_fd; | 1569 int fd, fd_max, n, i, ret, tcp_fd; |
1418 struct timeval tv; | 1570 struct timeval tv; |
1419 | 1571 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 *prtsp_st = rtsp_st; | 1605 *prtsp_st = rtsp_st; |
1454 return ret; | 1606 return ret; |
1455 } | 1607 } |
1456 } | 1608 } |
1457 } | 1609 } |
1458 } | 1610 } |
1459 #if CONFIG_RTSP_DEMUXER | 1611 #if CONFIG_RTSP_DEMUXER |
1460 if (tcp_fd != -1 && FD_ISSET(tcp_fd, &rfds)) { | 1612 if (tcp_fd != -1 && FD_ISSET(tcp_fd, &rfds)) { |
1461 RTSPMessageHeader reply; | 1613 RTSPMessageHeader reply; |
1462 | 1614 |
1463 rtsp_read_reply(s, &reply, NULL, 0); | 1615 ff_rtsp_read_reply(s, &reply, NULL, 0); |
1464 /* XXX: parse message */ | 1616 /* XXX: parse message */ |
1465 if (rt->state != RTSP_STATE_PLAYING) | 1617 if (rt->state != RTSP_STATE_STREAMING) |
1466 return 0; | 1618 return 0; |
1467 } | 1619 } |
1468 #endif | 1620 #endif |
1469 } | 1621 } |
1470 } | 1622 } |
1471 } | 1623 } |
1472 | 1624 |
1473 static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, | 1625 static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, |
1474 uint8_t *buf, int buf_size) | 1626 uint8_t *buf, int buf_size) |
1475 { | 1627 { |
1476 RTSPState *rt = s->priv_data; | 1628 RTSPState *rt = s->priv_data; |
1477 int id, len, i, ret; | 1629 int id, len, i, ret; |
1478 RTSPStream *rtsp_st; | 1630 RTSPStream *rtsp_st; |
1479 | 1631 |
1480 #ifdef DEBUG_RTP_TCP | 1632 #ifdef DEBUG_RTP_TCP |
1481 dprintf(s, "tcp_read_packet:\n"); | 1633 dprintf(s, "tcp_read_packet:\n"); |
1482 #endif | 1634 #endif |
1483 redo: | 1635 redo: |
1484 for (;;) { | 1636 for (;;) { |
1485 RTSPMessageHeader reply; | 1637 RTSPMessageHeader reply; |
1486 | 1638 |
1487 ret = rtsp_read_reply(s, &reply, NULL, 1); | 1639 ret = ff_rtsp_read_reply(s, &reply, NULL, 1); |
1488 if (ret == -1) | 1640 if (ret == -1) |
1489 return -1; | 1641 return -1; |
1490 if (ret == 1) /* received '$' */ | 1642 if (ret == 1) /* received '$' */ |
1491 break; | 1643 break; |
1492 /* XXX: parse message */ | 1644 /* XXX: parse message */ |
1493 if (rt->state != RTSP_STATE_PLAYING) | 1645 if (rt->state != RTSP_STATE_STREAMING) |
1494 return 0; | 1646 return 0; |
1495 } | 1647 } |
1496 ret = url_read_complete(rt->rtsp_hd, buf, 3); | 1648 ret = url_read_complete(rt->rtsp_hd, buf, 3); |
1497 if (ret != 3) | 1649 if (ret != 3) |
1498 return -1; | 1650 return -1; |
1499 id = buf[0]; | 1651 id = buf[0]; |
1500 len = AV_RB16(buf + 1); | 1652 len = AV_RB16(buf + 1); |
1501 #ifdef DEBUG_RTP_TCP | 1653 #ifdef DEBUG_RTP_TCP |
1502 dprintf(s, "id=%d len=%d\n", id, len); | 1654 dprintf(s, "id=%d len=%d\n", id, len); |
1503 #endif | 1655 #endif |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1593 for (i = 0; i < s->nb_streams; i++) | 1745 for (i = 0; i < s->nb_streams; i++) |
1594 cache[i] = s->streams[i]->discard; | 1746 cache[i] = s->streams[i]->discard; |
1595 | 1747 |
1596 if (!rt->need_subscription) { | 1748 if (!rt->need_subscription) { |
1597 if (memcmp (cache, rt->real_setup_cache, | 1749 if (memcmp (cache, rt->real_setup_cache, |
1598 sizeof(enum AVDiscard) * s->nb_streams)) { | 1750 sizeof(enum AVDiscard) * s->nb_streams)) { |
1599 snprintf(cmd, sizeof(cmd), | 1751 snprintf(cmd, sizeof(cmd), |
1600 "SET_PARAMETER %s RTSP/1.0\r\n" | 1752 "SET_PARAMETER %s RTSP/1.0\r\n" |
1601 "Unsubscribe: %s\r\n", | 1753 "Unsubscribe: %s\r\n", |
1602 rt->control_uri, rt->last_subscription); | 1754 rt->control_uri, rt->last_subscription); |
1603 rtsp_send_cmd(s, cmd, reply, NULL); | 1755 ff_rtsp_send_cmd(s, cmd, reply, NULL); |
1604 if (reply->status_code != RTSP_STATUS_OK) | 1756 if (reply->status_code != RTSP_STATUS_OK) |
1605 return AVERROR_INVALIDDATA; | 1757 return AVERROR_INVALIDDATA; |
1606 rt->need_subscription = 1; | 1758 rt->need_subscription = 1; |
1607 } | 1759 } |
1608 } | 1760 } |
1609 | 1761 |
1610 if (rt->need_subscription) { | 1762 if (rt->need_subscription) { |
1611 int r, rule_nr, first = 1; | 1763 int r, rule_nr, first = 1; |
1612 | 1764 |
1613 memcpy(rt->real_setup_cache, cache, | 1765 memcpy(rt->real_setup_cache, cache, |
(...skipping 15 matching lines...) Expand all Loading... |
1629 ff_rdt_subscribe_rule( | 1781 ff_rdt_subscribe_rule( |
1630 rt->last_subscription, | 1782 rt->last_subscription, |
1631 sizeof(rt->last_subscription), i, rule_nr); | 1783 sizeof(rt->last_subscription), i, rule_nr); |
1632 first = 0; | 1784 first = 0; |
1633 } | 1785 } |
1634 rule_nr++; | 1786 rule_nr++; |
1635 } | 1787 } |
1636 } | 1788 } |
1637 } | 1789 } |
1638 av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription); | 1790 av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription); |
1639 rtsp_send_cmd(s, cmd, reply, NULL); | 1791 ff_rtsp_send_cmd(s, cmd, reply, NULL); |
1640 if (reply->status_code != RTSP_STATUS_OK) | 1792 if (reply->status_code != RTSP_STATUS_OK) |
1641 return AVERROR_INVALIDDATA; | 1793 return AVERROR_INVALIDDATA; |
1642 rt->need_subscription = 0; | 1794 rt->need_subscription = 0; |
1643 | 1795 |
1644 if (rt->state == RTSP_STATE_PLAYING) | 1796 if (rt->state == RTSP_STATE_STREAMING) |
1645 rtsp_read_play (s); | 1797 rtsp_read_play (s); |
1646 } | 1798 } |
1647 } | 1799 } |
1648 | 1800 |
1649 ret = rtsp_fetch_packet(s, pkt); | 1801 ret = rtsp_fetch_packet(s, pkt); |
1650 if (ret < 0) | 1802 if (ret < 0) |
1651 return ret; | 1803 return ret; |
1652 | 1804 |
1653 /* send dummy request to keep TCP connection alive */ | 1805 /* send dummy request to keep TCP connection alive */ |
1654 if ((rt->server_type == RTSP_SERVER_WMS || | 1806 if ((rt->server_type == RTSP_SERVER_WMS || |
1655 rt->server_type == RTSP_SERVER_REAL) && | 1807 rt->server_type == RTSP_SERVER_REAL) && |
1656 (av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) { | 1808 (av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) { |
1657 if (rt->server_type == RTSP_SERVER_WMS) { | 1809 if (rt->server_type == RTSP_SERVER_WMS) { |
1658 snprintf(cmd, sizeof(cmd) - 1, | 1810 snprintf(cmd, sizeof(cmd) - 1, |
1659 "GET_PARAMETER %s RTSP/1.0\r\n", | 1811 "GET_PARAMETER %s RTSP/1.0\r\n", |
1660 rt->control_uri); | 1812 rt->control_uri); |
1661 rtsp_send_cmd_async(s, cmd); | 1813 ff_rtsp_send_cmd_async(s, cmd); |
1662 } else { | 1814 } else { |
1663 rtsp_send_cmd_async(s, "OPTIONS * RTSP/1.0\r\n"); | 1815 ff_rtsp_send_cmd_async(s, "OPTIONS * RTSP/1.0\r\n"); |
1664 } | 1816 } |
1665 } | 1817 } |
1666 | 1818 |
1667 return 0; | 1819 return 0; |
1668 } | 1820 } |
1669 | 1821 |
1670 /* pause the stream */ | 1822 /* pause the stream */ |
1671 static int rtsp_read_pause(AVFormatContext *s) | 1823 static int rtsp_read_pause(AVFormatContext *s) |
1672 { | 1824 { |
1673 RTSPState *rt = s->priv_data; | 1825 RTSPState *rt = s->priv_data; |
1674 RTSPMessageHeader reply1, *reply = &reply1; | 1826 RTSPMessageHeader reply1, *reply = &reply1; |
1675 char cmd[1024]; | 1827 char cmd[1024]; |
1676 | 1828 |
1677 rt = s->priv_data; | 1829 rt = s->priv_data; |
1678 | 1830 |
1679 if (rt->state != RTSP_STATE_PLAYING) | 1831 if (rt->state != RTSP_STATE_STREAMING) |
1680 return 0; | 1832 return 0; |
1681 else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) { | 1833 else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) { |
1682 snprintf(cmd, sizeof(cmd), | 1834 snprintf(cmd, sizeof(cmd), |
1683 "PAUSE %s RTSP/1.0\r\n", | 1835 "PAUSE %s RTSP/1.0\r\n", |
1684 rt->control_uri); | 1836 rt->control_uri); |
1685 rtsp_send_cmd(s, cmd, reply, NULL); | 1837 ff_rtsp_send_cmd(s, cmd, reply, NULL); |
1686 if (reply->status_code != RTSP_STATUS_OK) { | 1838 if (reply->status_code != RTSP_STATUS_OK) { |
1687 return -1; | 1839 return -1; |
1688 } | 1840 } |
1689 } | 1841 } |
1690 rt->state = RTSP_STATE_PAUSED; | 1842 rt->state = RTSP_STATE_PAUSED; |
1691 return 0; | 1843 return 0; |
1692 } | 1844 } |
1693 | 1845 |
1694 static int rtsp_read_seek(AVFormatContext *s, int stream_index, | 1846 static int rtsp_read_seek(AVFormatContext *s, int stream_index, |
1695 int64_t timestamp, int flags) | 1847 int64_t timestamp, int flags) |
1696 { | 1848 { |
1697 RTSPState *rt = s->priv_data; | 1849 RTSPState *rt = s->priv_data; |
1698 | 1850 |
1699 rt->seek_timestamp = av_rescale_q(timestamp, | 1851 rt->seek_timestamp = av_rescale_q(timestamp, |
1700 s->streams[stream_index]->time_base, | 1852 s->streams[stream_index]->time_base, |
1701 AV_TIME_BASE_Q); | 1853 AV_TIME_BASE_Q); |
1702 switch(rt->state) { | 1854 switch(rt->state) { |
1703 default: | 1855 default: |
1704 case RTSP_STATE_IDLE: | 1856 case RTSP_STATE_IDLE: |
1705 break; | 1857 break; |
1706 case RTSP_STATE_PLAYING: | 1858 case RTSP_STATE_STREAMING: |
1707 if (rtsp_read_pause(s) != 0) | 1859 if (rtsp_read_pause(s) != 0) |
1708 return -1; | 1860 return -1; |
1709 rt->state = RTSP_STATE_SEEKING; | 1861 rt->state = RTSP_STATE_SEEKING; |
1710 if (rtsp_read_play(s) != 0) | 1862 if (rtsp_read_play(s) != 0) |
1711 return -1; | 1863 return -1; |
1712 break; | 1864 break; |
1713 case RTSP_STATE_PAUSED: | 1865 case RTSP_STATE_PAUSED: |
1714 rt->state = RTSP_STATE_IDLE; | 1866 rt->state = RTSP_STATE_IDLE; |
1715 break; | 1867 break; |
1716 } | 1868 } |
1717 return 0; | 1869 return 0; |
1718 } | 1870 } |
1719 | 1871 |
1720 static int rtsp_read_close(AVFormatContext *s) | 1872 static int rtsp_read_close(AVFormatContext *s) |
1721 { | 1873 { |
1722 RTSPState *rt = s->priv_data; | 1874 RTSPState *rt = s->priv_data; |
1723 char cmd[1024]; | 1875 char cmd[1024]; |
1724 | 1876 |
1725 #if 0 | 1877 #if 0 |
1726 /* NOTE: it is valid to flush the buffer here */ | 1878 /* NOTE: it is valid to flush the buffer here */ |
1727 if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { | 1879 if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { |
1728 url_fclose(&rt->rtsp_gb); | 1880 url_fclose(&rt->rtsp_gb); |
1729 } | 1881 } |
1730 #endif | 1882 #endif |
1731 snprintf(cmd, sizeof(cmd), | 1883 snprintf(cmd, sizeof(cmd), |
1732 "TEARDOWN %s RTSP/1.0\r\n", | 1884 "TEARDOWN %s RTSP/1.0\r\n", |
1733 s->filename); | 1885 s->filename); |
1734 rtsp_send_cmd_async(s, cmd); | 1886 ff_rtsp_send_cmd_async(s, cmd); |
1735 | 1887 |
1736 rtsp_close_streams(rt); | 1888 ff_rtsp_close_streams(s); |
1737 url_close(rt->rtsp_hd); | 1889 url_close(rt->rtsp_hd); |
| 1890 ff_network_close(); |
1738 return 0; | 1891 return 0; |
1739 } | 1892 } |
1740 | 1893 |
1741 AVInputFormat rtsp_demuxer = { | 1894 AVInputFormat rtsp_demuxer = { |
1742 "rtsp", | 1895 "rtsp", |
1743 NULL_IF_CONFIG_SMALL("RTSP input format"), | 1896 NULL_IF_CONFIG_SMALL("RTSP input format"), |
1744 sizeof(RTSPState), | 1897 sizeof(RTSPState), |
1745 rtsp_probe, | 1898 rtsp_probe, |
1746 rtsp_read_header, | 1899 rtsp_read_header, |
1747 rtsp_read_packet, | 1900 rtsp_read_packet, |
(...skipping 27 matching lines...) Expand all Loading... |
1775 #define SDP_MAX_SIZE 8192 | 1928 #define SDP_MAX_SIZE 8192 |
1776 | 1929 |
1777 static int sdp_read_header(AVFormatContext *s, AVFormatParameters *ap) | 1930 static int sdp_read_header(AVFormatContext *s, AVFormatParameters *ap) |
1778 { | 1931 { |
1779 RTSPState *rt = s->priv_data; | 1932 RTSPState *rt = s->priv_data; |
1780 RTSPStream *rtsp_st; | 1933 RTSPStream *rtsp_st; |
1781 int size, i, err; | 1934 int size, i, err; |
1782 char *content; | 1935 char *content; |
1783 char url[1024]; | 1936 char url[1024]; |
1784 | 1937 |
| 1938 if (!ff_network_init()) |
| 1939 return AVERROR(EIO); |
| 1940 |
1785 /* read the whole sdp file */ | 1941 /* read the whole sdp file */ |
1786 /* XXX: better loading */ | 1942 /* XXX: better loading */ |
1787 content = av_malloc(SDP_MAX_SIZE); | 1943 content = av_malloc(SDP_MAX_SIZE); |
1788 size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1); | 1944 size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1); |
1789 if (size <= 0) { | 1945 if (size <= 0) { |
1790 av_free(content); | 1946 av_free(content); |
1791 return AVERROR_INVALIDDATA; | 1947 return AVERROR_INVALIDDATA; |
1792 } | 1948 } |
1793 content[size] ='\0'; | 1949 content[size] ='\0'; |
1794 | 1950 |
1795 sdp_parse(s, content); | 1951 sdp_parse(s, content); |
1796 av_free(content); | 1952 av_free(content); |
1797 | 1953 |
1798 /* open each RTP stream */ | 1954 /* open each RTP stream */ |
1799 for (i = 0; i < rt->nb_rtsp_streams; i++) { | 1955 for (i = 0; i < rt->nb_rtsp_streams; i++) { |
1800 rtsp_st = rt->rtsp_streams[i]; | 1956 rtsp_st = rt->rtsp_streams[i]; |
1801 | 1957 |
1802 snprintf(url, sizeof(url), "rtp://%s:%d?localport=%d&ttl=%d", | 1958 ff_url_join(url, sizeof(url), "rtp", NULL, |
1803 inet_ntoa(rtsp_st->sdp_ip), | 1959 inet_ntoa(rtsp_st->sdp_ip), rtsp_st->sdp_port, |
1804 rtsp_st->sdp_port, | 1960 "?localport=%d&ttl=%d", rtsp_st->sdp_port, |
1805 rtsp_st->sdp_port, | 1961 rtsp_st->sdp_ttl); |
1806 rtsp_st->sdp_ttl); | |
1807 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { | 1962 if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { |
1808 err = AVERROR_INVALIDDATA; | 1963 err = AVERROR_INVALIDDATA; |
1809 goto fail; | 1964 goto fail; |
1810 } | 1965 } |
1811 if ((err = rtsp_open_transport_ctx(s, rtsp_st))) | 1966 if ((err = rtsp_open_transport_ctx(s, rtsp_st))) |
1812 goto fail; | 1967 goto fail; |
1813 } | 1968 } |
1814 return 0; | 1969 return 0; |
1815 fail: | 1970 fail: |
1816 rtsp_close_streams(rt); | 1971 ff_rtsp_close_streams(s); |
| 1972 ff_network_close(); |
1817 return err; | 1973 return err; |
1818 } | 1974 } |
1819 | 1975 |
1820 static int sdp_read_close(AVFormatContext *s) | 1976 static int sdp_read_close(AVFormatContext *s) |
1821 { | 1977 { |
1822 RTSPState *rt = s->priv_data; | 1978 ff_rtsp_close_streams(s); |
1823 rtsp_close_streams(rt); | 1979 ff_network_close(); |
1824 return 0; | 1980 return 0; |
1825 } | 1981 } |
1826 | 1982 |
1827 AVInputFormat sdp_demuxer = { | 1983 AVInputFormat sdp_demuxer = { |
1828 "sdp", | 1984 "sdp", |
1829 NULL_IF_CONFIG_SMALL("SDP"), | 1985 NULL_IF_CONFIG_SMALL("SDP"), |
1830 sizeof(RTSPState), | 1986 sizeof(RTSPState), |
1831 sdp_probe, | 1987 sdp_probe, |
1832 sdp_read_header, | 1988 sdp_read_header, |
1833 rtsp_fetch_packet, | 1989 rtsp_fetch_packet, |
1834 sdp_read_close, | 1990 sdp_read_close, |
1835 }; | 1991 }; |
OLD | NEW |