| 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. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 #include "rtsp.h" | 37 #include "rtsp.h" |
| 38 | 38 |
| 39 #include "rtpdec.h" | 39 #include "rtpdec.h" |
| 40 #include "rdt.h" | 40 #include "rdt.h" |
| 41 #include "rtpdec_formats.h" | 41 #include "rtpdec_formats.h" |
| 42 #include "rtpenc_chain.h" | 42 #include "rtpenc_chain.h" |
| 43 | 43 |
| 44 //#define DEBUG | 44 //#define DEBUG |
| 45 //#define DEBUG_RTP_TCP | 45 //#define DEBUG_RTP_TCP |
| 46 | 46 |
| 47 #if LIBAVFORMAT_VERSION_INT < (53 << 16) | |
| 48 int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP); | |
| 49 #endif | |
| 50 | |
| 51 /* Timeout values for socket select, in ms, | 47 /* Timeout values for socket select, in ms, |
| 52 * and read_packet(), in seconds */ | 48 * and read_packet(), in seconds */ |
| 53 #define SELECT_TIMEOUT_MS 100 | 49 #define SELECT_TIMEOUT_MS 100 |
| 54 #define READ_PACKET_TIMEOUT_S 10 | 50 #define READ_PACKET_TIMEOUT_S 10 |
| 55 #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / SELECT_TIMEOUT_MS | 51 #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / SELECT_TIMEOUT_MS |
| 56 #define SDP_MAX_SIZE 16384 | 52 #define SDP_MAX_SIZE 16384 |
| 57 #define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH | 53 #define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH |
| 58 | 54 |
| 59 static void get_word_until_chars(char *buf, int buf_size, | 55 static void get_word_until_chars(char *buf, int buf_size, |
| 60 const char *sep, const char **pp) | 56 const char *sep, const char **pp) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 80 { | 76 { |
| 81 if (**pp == '/') (*pp)++; | 77 if (**pp == '/') (*pp)++; |
| 82 get_word_until_chars(buf, buf_size, sep, pp); | 78 get_word_until_chars(buf, buf_size, sep, pp); |
| 83 } | 79 } |
| 84 | 80 |
| 85 static void get_word(char *buf, int buf_size, const char **pp) | 81 static void get_word(char *buf, int buf_size, const char **pp) |
| 86 { | 82 { |
| 87 get_word_until_chars(buf, buf_size, SPACE_CHARS, pp); | 83 get_word_until_chars(buf, buf_size, SPACE_CHARS, pp); |
| 88 } | 84 } |
| 89 | 85 |
| 86 /** Parse a string p in the form of Range:npt=xx-xx, and determine the start |
| 87 * and end time. |
| 88 * Used for seeking in the rtp stream. |
| 89 */ |
| 90 static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) |
| 91 { |
| 92 char buf[256]; |
| 93 |
| 94 p += strspn(p, SPACE_CHARS); |
| 95 if (!av_stristart(p, "npt=", &p)) |
| 96 return; |
| 97 |
| 98 *start = AV_NOPTS_VALUE; |
| 99 *end = AV_NOPTS_VALUE; |
| 100 |
| 101 get_word_sep(buf, sizeof(buf), "-", &p); |
| 102 *start = parse_date(buf, 1); |
| 103 if (*p == '-') { |
| 104 p++; |
| 105 get_word_sep(buf, sizeof(buf), "-", &p); |
| 106 *end = parse_date(buf, 1); |
| 107 } |
| 108 // av_log(NULL, AV_LOG_DEBUG, "Range Start: %lld\n", *start); |
| 109 // av_log(NULL, AV_LOG_DEBUG, "Range End: %lld\n", *end); |
| 110 } |
| 111 |
| 112 static int get_sockaddr(const char *buf, struct sockaddr_storage *sock) |
| 113 { |
| 114 struct addrinfo hints, *ai = NULL; |
| 115 memset(&hints, 0, sizeof(hints)); |
| 116 hints.ai_flags = AI_NUMERICHOST; |
| 117 if (getaddrinfo(buf, NULL, &hints, &ai)) |
| 118 return -1; |
| 119 memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen)); |
| 120 freeaddrinfo(ai); |
| 121 return 0; |
| 122 } |
| 123 |
| 124 #if CONFIG_RTPDEC |
| 90 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */ | 125 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */ |
| 91 static int sdp_parse_rtpmap(AVFormatContext *s, | 126 static int sdp_parse_rtpmap(AVFormatContext *s, |
| 92 AVCodecContext *codec, RTSPStream *rtsp_st, | 127 AVCodecContext *codec, RTSPStream *rtsp_st, |
| 93 int payload_type, const char *p) | 128 int payload_type, const char *p) |
| 94 { | 129 { |
| 95 char buf[256]; | 130 char buf[256]; |
| 96 int i; | 131 int i; |
| 97 AVCodec *c; | 132 AVCodec *c; |
| 98 const char *c_name; | 133 const char *c_name; |
| 99 | 134 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 if (**p == '=') | 214 if (**p == '=') |
| 180 (*p)++; | 215 (*p)++; |
| 181 get_word_sep(value, value_size, ";", p); | 216 get_word_sep(value, value_size, ";", p); |
| 182 if (**p == ';') | 217 if (**p == ';') |
| 183 (*p)++; | 218 (*p)++; |
| 184 return 1; | 219 return 1; |
| 185 } | 220 } |
| 186 return 0; | 221 return 0; |
| 187 } | 222 } |
| 188 | 223 |
| 189 /** Parse a string p in the form of Range:npt=xx-xx, and determine the start | |
| 190 * and end time. | |
| 191 * Used for seeking in the rtp stream. | |
| 192 */ | |
| 193 static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) | |
| 194 { | |
| 195 char buf[256]; | |
| 196 | |
| 197 p += strspn(p, SPACE_CHARS); | |
| 198 if (!av_stristart(p, "npt=", &p)) | |
| 199 return; | |
| 200 | |
| 201 *start = AV_NOPTS_VALUE; | |
| 202 *end = AV_NOPTS_VALUE; | |
| 203 | |
| 204 get_word_sep(buf, sizeof(buf), "-", &p); | |
| 205 *start = parse_date(buf, 1); | |
| 206 if (*p == '-') { | |
| 207 p++; | |
| 208 get_word_sep(buf, sizeof(buf), "-", &p); | |
| 209 *end = parse_date(buf, 1); | |
| 210 } | |
| 211 // av_log(NULL, AV_LOG_DEBUG, "Range Start: %lld\n", *start); | |
| 212 // av_log(NULL, AV_LOG_DEBUG, "Range End: %lld\n", *end); | |
| 213 } | |
| 214 | |
| 215 static int get_sockaddr(const char *buf, struct sockaddr_storage *sock) | |
| 216 { | |
| 217 struct addrinfo hints, *ai = NULL; | |
| 218 memset(&hints, 0, sizeof(hints)); | |
| 219 hints.ai_flags = AI_NUMERICHOST; | |
| 220 if (getaddrinfo(buf, NULL, &hints, &ai)) | |
| 221 return -1; | |
| 222 memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen)); | |
| 223 freeaddrinfo(ai); | |
| 224 return 0; | |
| 225 } | |
| 226 | |
| 227 typedef struct SDPParseState { | 224 typedef struct SDPParseState { |
| 228 /* SDP only */ | 225 /* SDP only */ |
| 229 struct sockaddr_storage default_ip; | 226 struct sockaddr_storage default_ip; |
| 230 int default_ttl; | 227 int default_ttl; |
| 231 int skip_media; ///< set if an unknown m= line occurs | 228 int skip_media; ///< set if an unknown m= line occurs |
| 232 } SDPParseState; | 229 } SDPParseState; |
| 233 | 230 |
| 234 static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, | 231 static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, |
| 235 int letter, const char *buf) | 232 int letter, const char *buf) |
| 236 { | 233 { |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 *q = '\0'; | 447 *q = '\0'; |
| 451 sdp_parse_line(s, s1, letter, buf); | 448 sdp_parse_line(s, s1, letter, buf); |
| 452 next_line: | 449 next_line: |
| 453 while (*p != '\n' && *p != '\0') | 450 while (*p != '\n' && *p != '\0') |
| 454 p++; | 451 p++; |
| 455 if (*p == '\n') | 452 if (*p == '\n') |
| 456 p++; | 453 p++; |
| 457 } | 454 } |
| 458 return 0; | 455 return 0; |
| 459 } | 456 } |
| 457 #endif /* CONFIG_RTPDEC */ |
| 460 | 458 |
| 461 /* close and free RTSP streams */ | 459 /* close and free RTSP streams */ |
| 462 void ff_rtsp_close_streams(AVFormatContext *s) | 460 void ff_rtsp_close_streams(AVFormatContext *s) |
| 463 { | 461 { |
| 464 RTSPState *rt = s->priv_data; | 462 RTSPState *rt = s->priv_data; |
| 465 int i; | 463 int i; |
| 466 RTSPStream *rtsp_st; | 464 RTSPStream *rtsp_st; |
| 467 | 465 |
| 468 for (i = 0; i < rt->nb_rtsp_streams; i++) { | 466 for (i = 0; i < rt->nb_rtsp_streams; i++) { |
| 469 rtsp_st = rt->rtsp_streams[i]; | 467 rtsp_st = rt->rtsp_streams[i]; |
| 470 if (rtsp_st) { | 468 if (rtsp_st) { |
| 471 if (rtsp_st->transport_priv) { | 469 if (rtsp_st->transport_priv) { |
| 472 if (s->oformat) { | 470 if (s->oformat) { |
| 473 AVFormatContext *rtpctx = rtsp_st->transport_priv; | 471 AVFormatContext *rtpctx = rtsp_st->transport_priv; |
| 474 av_write_trailer(rtpctx); | 472 av_write_trailer(rtpctx); |
| 475 if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { | 473 if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { |
| 476 uint8_t *ptr; | 474 uint8_t *ptr; |
| 477 url_close_dyn_buf(rtpctx->pb, &ptr); | 475 url_close_dyn_buf(rtpctx->pb, &ptr); |
| 478 av_free(ptr); | 476 av_free(ptr); |
| 479 } else { | 477 } else { |
| 480 url_fclose(rtpctx->pb); | 478 url_fclose(rtpctx->pb); |
| 481 } | 479 } |
| 482 av_metadata_free(&rtpctx->streams[0]->metadata); | 480 av_metadata_free(&rtpctx->streams[0]->metadata); |
| 483 av_metadata_free(&rtpctx->metadata); | 481 av_metadata_free(&rtpctx->metadata); |
| 484 av_free(rtpctx->streams[0]); | 482 av_free(rtpctx->streams[0]); |
| 485 av_free(rtpctx); | 483 av_free(rtpctx); |
| 486 } else if (rt->transport == RTSP_TRANSPORT_RDT) | 484 } else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) |
| 487 ff_rdt_parse_close(rtsp_st->transport_priv); | 485 ff_rdt_parse_close(rtsp_st->transport_priv); |
| 488 else | 486 else if (CONFIG_RTPDEC) |
| 489 rtp_parse_close(rtsp_st->transport_priv); | 487 rtp_parse_close(rtsp_st->transport_priv); |
| 490 } | 488 } |
| 491 if (rtsp_st->rtp_handle) | 489 if (rtsp_st->rtp_handle) |
| 492 url_close(rtsp_st->rtp_handle); | 490 url_close(rtsp_st->rtp_handle); |
| 493 if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) | 491 if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) |
| 494 rtsp_st->dynamic_handler->close( | 492 rtsp_st->dynamic_handler->close( |
| 495 rtsp_st->dynamic_protocol_context); | 493 rtsp_st->dynamic_protocol_context); |
| 496 } | 494 } |
| 497 } | 495 } |
| 498 av_free(rt->rtsp_streams); | 496 av_free(rt->rtsp_streams); |
| 499 if (rt->asf_ctx) { | 497 if (rt->asf_ctx) { |
| 500 av_close_input_stream (rt->asf_ctx); | 498 av_close_input_stream (rt->asf_ctx); |
| 501 rt->asf_ctx = NULL; | 499 rt->asf_ctx = NULL; |
| 502 } | 500 } |
| 503 av_free(rt->recvbuf); | 501 av_free(rt->recvbuf); |
| 504 } | 502 } |
| 505 | 503 |
| 506 static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) | 504 static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) |
| 507 { | 505 { |
| 508 RTSPState *rt = s->priv_data; | 506 RTSPState *rt = s->priv_data; |
| 509 AVStream *st = NULL; | 507 AVStream *st = NULL; |
| 510 | 508 |
| 511 /* open the RTP context */ | 509 /* open the RTP context */ |
| 512 if (rtsp_st->stream_index >= 0) | 510 if (rtsp_st->stream_index >= 0) |
| 513 st = s->streams[rtsp_st->stream_index]; | 511 st = s->streams[rtsp_st->stream_index]; |
| 514 if (!st) | 512 if (!st) |
| 515 s->ctx_flags |= AVFMTCTX_NOHEADER; | 513 s->ctx_flags |= AVFMTCTX_NOHEADER; |
| 516 | 514 |
| 517 if (s->oformat) { | 515 if (s->oformat && CONFIG_RTSP_MUXER) { |
| 518 rtsp_st->transport_priv = ff_rtp_chain_mux_open(s, st, | 516 rtsp_st->transport_priv = ff_rtp_chain_mux_open(s, st, |
| 519 rtsp_st->rtp_handle, | 517 rtsp_st->rtp_handle, |
| 520 RTSP_TCP_MAX_PACKET_SIZE); | 518 RTSP_TCP_MAX_PACKET_SIZE); |
| 521 /* Ownership of rtp_handle is passed to the rtp mux context */ | 519 /* Ownership of rtp_handle is passed to the rtp mux context */ |
| 522 rtsp_st->rtp_handle = NULL; | 520 rtsp_st->rtp_handle = NULL; |
| 523 } else if (rt->transport == RTSP_TRANSPORT_RDT) | 521 } else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) |
| 524 rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, | 522 rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, |
| 525 rtsp_st->dynamic_protocol_context, | 523 rtsp_st->dynamic_protocol_context, |
| 526 rtsp_st->dynamic_handler); | 524 rtsp_st->dynamic_handler); |
| 527 else | 525 else if (CONFIG_RTPDEC) |
| 528 rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle, | 526 rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle, |
| 529 rtsp_st->sdp_payload_type, | 527 rtsp_st->sdp_payload_type, |
| 530 (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay) | 528 (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay) |
| 531 ? 0 : RTP_REORDER_QUEUE_DEFAULT_SIZE); | 529 ? 0 : RTP_REORDER_QUEUE_DEFAULT_SIZE); |
| 532 | 530 |
| 533 if (!rtsp_st->transport_priv) { | 531 if (!rtsp_st->transport_priv) { |
| 534 return AVERROR(ENOMEM); | 532 return AVERROR(ENOMEM); |
| 535 } else if (rt->transport != RTSP_TRANSPORT_RDT) { | 533 } else if (rt->transport != RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) { |
| 536 if (rtsp_st->dynamic_handler) { | 534 if (rtsp_st->dynamic_handler) { |
| 537 rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, | 535 rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, |
| 538 rtsp_st->dynamic_protocol_context, | 536 rtsp_st->dynamic_protocol_context, |
| 539 rtsp_st->dynamic_handler); | 537 rtsp_st->dynamic_handler); |
| 540 } | 538 } |
| 541 } | 539 } |
| 542 | 540 |
| 543 return 0; | 541 return 0; |
| 544 } | 542 } |
| 545 | 543 |
| 546 #if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER | 544 #if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER |
| 547 static int rtsp_probe(AVProbeData *p) | |
| 548 { | |
| 549 if (av_strstart(p->filename, "rtsp:", NULL)) | |
| 550 return AVPROBE_SCORE_MAX; | |
| 551 return 0; | |
| 552 } | |
| 553 | |
| 554 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) | 545 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) |
| 555 { | 546 { |
| 556 const char *p; | 547 const char *p; |
| 557 int v; | 548 int v; |
| 558 | 549 |
| 559 p = *pp; | 550 p = *pp; |
| 560 p += strspn(p, SPACE_CHARS); | 551 p += strspn(p, SPACE_CHARS); |
| 561 v = strtol(p, (char **)&p, 10); | 552 v = strtol(p, (char **)&p, 10); |
| 562 if (*p == '-') { | 553 if (*p == '-') { |
| 563 p++; | 554 p++; |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1017 | 1008 |
| 1018 #if 0 | 1009 #if 0 |
| 1019 /* then try on any port */ | 1010 /* then try on any port */ |
| 1020 if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { | 1011 if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { |
| 1021 err = AVERROR_INVALIDDATA; | 1012 err = AVERROR_INVALIDDATA; |
| 1022 goto fail; | 1013 goto fail; |
| 1023 } | 1014 } |
| 1024 #endif | 1015 #endif |
| 1025 | 1016 |
| 1026 rtp_opened: | 1017 rtp_opened: |
| 1027 port = rtp_get_local_port(rtsp_st->rtp_handle); | 1018 port = rtp_get_local_rtp_port(rtsp_st->rtp_handle); |
| 1028 have_port: | 1019 have_port: |
| 1029 snprintf(transport, sizeof(transport) - 1, | 1020 snprintf(transport, sizeof(transport) - 1, |
| 1030 "%s/UDP;", trans_pref); | 1021 "%s/UDP;", trans_pref); |
| 1031 if (rt->server_type != RTSP_SERVER_REAL) | 1022 if (rt->server_type != RTSP_SERVER_REAL) |
| 1032 av_strlcat(transport, "unicast;", sizeof(transport)); | 1023 av_strlcat(transport, "unicast;", sizeof(transport)); |
| 1033 av_strlcatf(transport, sizeof(transport), | 1024 av_strlcatf(transport, sizeof(transport), |
| 1034 "client_port=%d", port); | 1025 "client_port=%d", port); |
| 1035 if (rt->transport == RTSP_TRANSPORT_RTP && | 1026 if (rt->transport == RTSP_TRANSPORT_RTP && |
| 1036 !(rt->server_type == RTSP_SERVER_WMS && i > 0)) | 1027 !(rt->server_type == RTSP_SERVER_WMS && i > 0)) |
| 1037 av_strlcatf(transport, sizeof(transport), "-%d", port + 1); | 1028 av_strlcatf(transport, sizeof(transport), "-%d", port + 1); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1061 "%s/UDP;multicast", trans_pref); | 1052 "%s/UDP;multicast", trans_pref); |
| 1062 } | 1053 } |
| 1063 if (s->oformat) { | 1054 if (s->oformat) { |
| 1064 av_strlcat(transport, ";mode=receive", sizeof(transport)); | 1055 av_strlcat(transport, ";mode=receive", sizeof(transport)); |
| 1065 } else if (rt->server_type == RTSP_SERVER_REAL || | 1056 } else if (rt->server_type == RTSP_SERVER_REAL || |
| 1066 rt->server_type == RTSP_SERVER_WMS) | 1057 rt->server_type == RTSP_SERVER_WMS) |
| 1067 av_strlcat(transport, ";mode=play", sizeof(transport)); | 1058 av_strlcat(transport, ";mode=play", sizeof(transport)); |
| 1068 snprintf(cmd, sizeof(cmd), | 1059 snprintf(cmd, sizeof(cmd), |
| 1069 "Transport: %s\r\n", | 1060 "Transport: %s\r\n", |
| 1070 transport); | 1061 transport); |
| 1071 if (i == 0 && rt->server_type == RTSP_SERVER_REAL) { | 1062 if (i == 0 && rt->server_type == RTSP_SERVER_REAL && CONFIG_RTPDEC) { |
| 1072 char real_res[41], real_csum[9]; | 1063 char real_res[41], real_csum[9]; |
| 1073 ff_rdt_calc_response_and_checksum(real_res, real_csum, | 1064 ff_rdt_calc_response_and_checksum(real_res, real_csum, |
| 1074 real_challenge); | 1065 real_challenge); |
| 1075 av_strlcatf(cmd, sizeof(cmd), | 1066 av_strlcatf(cmd, sizeof(cmd), |
| 1076 "If-Match: %s\r\n" | 1067 "If-Match: %s\r\n" |
| 1077 "RealChallenge2: %s, sd=%s\r\n", | 1068 "RealChallenge2: %s, sd=%s\r\n", |
| 1078 rt->session_id, real_res, real_csum); | 1069 rt->session_id, real_res, real_csum); |
| 1079 } | 1070 } |
| 1080 ff_rtsp_send_cmd(s, "SETUP", rtsp_st->control_url, cmd, reply, NULL); | 1071 ff_rtsp_send_cmd(s, "SETUP", rtsp_st->control_url, cmd, reply, NULL); |
| 1081 if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { | 1072 if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1126 } | 1117 } |
| 1127 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && | 1118 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && |
| 1128 rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { | 1119 rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { |
| 1129 err = AVERROR_INVALIDDATA; | 1120 err = AVERROR_INVALIDDATA; |
| 1130 goto fail; | 1121 goto fail; |
| 1131 } | 1122 } |
| 1132 /* Try to initialize the connection state in a | 1123 /* Try to initialize the connection state in a |
| 1133 * potential NAT router by sending dummy packets. | 1124 * potential NAT router by sending dummy packets. |
| 1134 * RTP/RTCP dummy packets are used for RDT, too. | 1125 * RTP/RTCP dummy packets are used for RDT, too. |
| 1135 */ | 1126 */ |
| 1136 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && s->iformat) | 1127 if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && s->iformat && |
| 1128 CONFIG_RTPDEC) |
| 1137 rtp_send_punch_packets(rtsp_st->rtp_handle); | 1129 rtp_send_punch_packets(rtsp_st->rtp_handle); |
| 1138 break; | 1130 break; |
| 1139 } | 1131 } |
| 1140 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { | 1132 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { |
| 1141 char url[1024], namebuf[50]; | 1133 char url[1024], namebuf[50]; |
| 1142 struct sockaddr_storage addr; | 1134 struct sockaddr_storage addr; |
| 1143 int port, ttl; | 1135 int port, ttl; |
| 1144 | 1136 |
| 1145 if (reply->transports[0].destination.ss_family) { | 1137 if (reply->transports[0].destination.ss_family) { |
| 1146 addr = reply->transports[0].destination; | 1138 addr = reply->transports[0].destination; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1225 av_rescale_q(reply->range_start, AV_TIME_BASE_Q, | 1217 av_rescale_q(reply->range_start, AV_TIME_BASE_Q, |
| 1226 st->time_base); | 1218 st->time_base); |
| 1227 } | 1219 } |
| 1228 } | 1220 } |
| 1229 } | 1221 } |
| 1230 } | 1222 } |
| 1231 rt->state = RTSP_STATE_STREAMING; | 1223 rt->state = RTSP_STATE_STREAMING; |
| 1232 return 0; | 1224 return 0; |
| 1233 } | 1225 } |
| 1234 | 1226 |
| 1227 #if CONFIG_RTSP_DEMUXER |
| 1235 static int rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply
) | 1228 static int rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply
) |
| 1236 { | 1229 { |
| 1237 RTSPState *rt = s->priv_data; | 1230 RTSPState *rt = s->priv_data; |
| 1238 char cmd[1024]; | 1231 char cmd[1024]; |
| 1239 unsigned char *content = NULL; | 1232 unsigned char *content = NULL; |
| 1240 int ret; | 1233 int ret; |
| 1241 | 1234 |
| 1242 /* describe the stream */ | 1235 /* describe the stream */ |
| 1243 snprintf(cmd, sizeof(cmd), | 1236 snprintf(cmd, sizeof(cmd), |
| 1244 "Accept: application/sdp\r\n"); | 1237 "Accept: application/sdp\r\n"); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1261 | 1254 |
| 1262 av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content); | 1255 av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content); |
| 1263 /* now we got the SDP description, we parse it */ | 1256 /* now we got the SDP description, we parse it */ |
| 1264 ret = sdp_parse(s, (const char *)content); | 1257 ret = sdp_parse(s, (const char *)content); |
| 1265 av_freep(&content); | 1258 av_freep(&content); |
| 1266 if (ret < 0) | 1259 if (ret < 0) |
| 1267 return AVERROR_INVALIDDATA; | 1260 return AVERROR_INVALIDDATA; |
| 1268 | 1261 |
| 1269 return 0; | 1262 return 0; |
| 1270 } | 1263 } |
| 1264 #endif /* CONFIG_RTSP_DEMUXER */ |
| 1271 | 1265 |
| 1266 #if CONFIG_RTSP_MUXER |
| 1272 static int rtsp_setup_output_streams(AVFormatContext *s, const char *addr) | 1267 static int rtsp_setup_output_streams(AVFormatContext *s, const char *addr) |
| 1273 { | 1268 { |
| 1274 RTSPState *rt = s->priv_data; | 1269 RTSPState *rt = s->priv_data; |
| 1275 RTSPMessageHeader reply1, *reply = &reply1; | 1270 RTSPMessageHeader reply1, *reply = &reply1; |
| 1276 int i; | 1271 int i; |
| 1277 char *sdp; | 1272 char *sdp; |
| 1278 AVFormatContext sdp_ctx, *ctx_array[1]; | 1273 AVFormatContext sdp_ctx, *ctx_array[1]; |
| 1279 | 1274 |
| 1280 s->start_time_realtime = av_gettime(); | 1275 s->start_time_realtime = av_gettime(); |
| 1281 | 1276 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1325 rtsp_st->stream_index = i; | 1320 rtsp_st->stream_index = i; |
| 1326 | 1321 |
| 1327 av_strlcpy(rtsp_st->control_url, rt->control_uri, sizeof(rtsp_st->contro
l_url)); | 1322 av_strlcpy(rtsp_st->control_url, rt->control_uri, sizeof(rtsp_st->contro
l_url)); |
| 1328 /* Note, this must match the relative uri set in the sdp content */ | 1323 /* Note, this must match the relative uri set in the sdp content */ |
| 1329 av_strlcatf(rtsp_st->control_url, sizeof(rtsp_st->control_url), | 1324 av_strlcatf(rtsp_st->control_url, sizeof(rtsp_st->control_url), |
| 1330 "/streamid=%d", i); | 1325 "/streamid=%d", i); |
| 1331 } | 1326 } |
| 1332 | 1327 |
| 1333 return 0; | 1328 return 0; |
| 1334 } | 1329 } |
| 1330 #endif /* CONFIG_RTSP_MUXER */ |
| 1335 | 1331 |
| 1336 void ff_rtsp_close_connections(AVFormatContext *s) | 1332 void ff_rtsp_close_connections(AVFormatContext *s) |
| 1337 { | 1333 { |
| 1338 RTSPState *rt = s->priv_data; | 1334 RTSPState *rt = s->priv_data; |
| 1339 if (rt->rtsp_hd_out != rt->rtsp_hd) url_close(rt->rtsp_hd_out); | 1335 if (rt->rtsp_hd_out != rt->rtsp_hd) url_close(rt->rtsp_hd_out); |
| 1340 url_close(rt->rtsp_hd); | 1336 url_close(rt->rtsp_hd); |
| 1341 rt->rtsp_hd = rt->rtsp_hd_out = NULL; | 1337 rt->rtsp_hd = rt->rtsp_hd_out = NULL; |
| 1342 } | 1338 } |
| 1343 | 1339 |
| 1344 int ff_rtsp_connect(AVFormatContext *s) | 1340 int ff_rtsp_connect(AVFormatContext *s) |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1541 if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { | 1537 if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { |
| 1542 rt->server_type = RTSP_SERVER_REAL; | 1538 rt->server_type = RTSP_SERVER_REAL; |
| 1543 continue; | 1539 continue; |
| 1544 } else if (!strncasecmp(reply->server, "WMServer/", 9)) { | 1540 } else if (!strncasecmp(reply->server, "WMServer/", 9)) { |
| 1545 rt->server_type = RTSP_SERVER_WMS; | 1541 rt->server_type = RTSP_SERVER_WMS; |
| 1546 } else if (rt->server_type == RTSP_SERVER_REAL) | 1542 } else if (rt->server_type == RTSP_SERVER_REAL) |
| 1547 strcpy(real_challenge, reply->real_challenge); | 1543 strcpy(real_challenge, reply->real_challenge); |
| 1548 break; | 1544 break; |
| 1549 } | 1545 } |
| 1550 | 1546 |
| 1551 if (s->iformat) | 1547 if (s->iformat && CONFIG_RTSP_DEMUXER) |
| 1552 err = rtsp_setup_input_streams(s, reply); | 1548 err = rtsp_setup_input_streams(s, reply); |
| 1553 else | 1549 else if (CONFIG_RTSP_MUXER) |
| 1554 err = rtsp_setup_output_streams(s, host); | 1550 err = rtsp_setup_output_streams(s, host); |
| 1555 if (err) | 1551 if (err) |
| 1556 goto fail; | 1552 goto fail; |
| 1557 | 1553 |
| 1558 do { | 1554 do { |
| 1559 int lower_transport = ff_log2_tab[lower_transport_mask & | 1555 int lower_transport = ff_log2_tab[lower_transport_mask & |
| 1560 ~(lower_transport_mask - 1)]; | 1556 ~(lower_transport_mask - 1)]; |
| 1561 | 1557 |
| 1562 err = make_setup_request(s, host, port, lower_transport, | 1558 err = make_setup_request(s, host, port, lower_transport, |
| 1563 rt->server_type == RTSP_SERVER_REAL ? | 1559 rt->server_type == RTSP_SERVER_REAL ? |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1582 av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", | 1578 av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", |
| 1583 reply->status_code, | 1579 reply->status_code, |
| 1584 s->filename); | 1580 s->filename); |
| 1585 goto redirect; | 1581 goto redirect; |
| 1586 } | 1582 } |
| 1587 ff_network_close(); | 1583 ff_network_close(); |
| 1588 return err; | 1584 return err; |
| 1589 } | 1585 } |
| 1590 #endif /* CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER */ | 1586 #endif /* CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER */ |
| 1591 | 1587 |
| 1588 #if CONFIG_RTPDEC |
| 1592 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, | 1589 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, |
| 1593 uint8_t *buf, int buf_size, int64_t wait_end) | 1590 uint8_t *buf, int buf_size, int64_t wait_end) |
| 1594 { | 1591 { |
| 1595 RTSPState *rt = s->priv_data; | 1592 RTSPState *rt = s->priv_data; |
| 1596 RTSPStream *rtsp_st; | 1593 RTSPStream *rtsp_st; |
| 1597 fd_set rfds; | 1594 fd_set rfds; |
| 1598 int fd, fd_rtcp, fd_max, n, i, ret, tcp_fd, timeout_cnt = 0; | 1595 int fd, fd_rtcp, fd_max, n, i, ret, tcp_fd, timeout_cnt = 0; |
| 1599 struct timeval tv; | 1596 struct timeval tv; |
| 1600 | 1597 |
| 1601 for (;;) { | 1598 for (;;) { |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1770 } | 1767 } |
| 1771 end: | 1768 end: |
| 1772 if (ret < 0) | 1769 if (ret < 0) |
| 1773 goto redo; | 1770 goto redo; |
| 1774 if (ret == 1) | 1771 if (ret == 1) |
| 1775 /* more packets may follow, so we save the RTP context */ | 1772 /* more packets may follow, so we save the RTP context */ |
| 1776 rt->cur_transport_priv = rtsp_st->transport_priv; | 1773 rt->cur_transport_priv = rtsp_st->transport_priv; |
| 1777 | 1774 |
| 1778 return ret; | 1775 return ret; |
| 1779 } | 1776 } |
| 1777 #endif /* CONFIG_RTPDEC */ |
| 1780 | 1778 |
| 1781 #if CONFIG_RTSP_DEMUXER | 1779 #if CONFIG_RTSP_DEMUXER |
| 1780 static int rtsp_probe(AVProbeData *p) |
| 1781 { |
| 1782 if (av_strstart(p->filename, "rtsp:", NULL)) |
| 1783 return AVPROBE_SCORE_MAX; |
| 1784 return 0; |
| 1785 } |
| 1786 |
| 1782 static int rtsp_read_header(AVFormatContext *s, | 1787 static int rtsp_read_header(AVFormatContext *s, |
| 1783 AVFormatParameters *ap) | 1788 AVFormatParameters *ap) |
| 1784 { | 1789 { |
| 1785 RTSPState *rt = s->priv_data; | 1790 RTSPState *rt = s->priv_data; |
| 1786 int ret; | 1791 int ret; |
| 1787 | 1792 |
| 1788 ret = ff_rtsp_connect(s); | 1793 ret = ff_rtsp_connect(s); |
| 1789 if (ret) | 1794 if (ret) |
| 1790 return ret; | 1795 return ret; |
| 1791 | 1796 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2013 rtsp_read_header, | 2018 rtsp_read_header, |
| 2014 rtsp_read_packet, | 2019 rtsp_read_packet, |
| 2015 rtsp_read_close, | 2020 rtsp_read_close, |
| 2016 rtsp_read_seek, | 2021 rtsp_read_seek, |
| 2017 .flags = AVFMT_NOFILE, | 2022 .flags = AVFMT_NOFILE, |
| 2018 .read_play = rtsp_read_play, | 2023 .read_play = rtsp_read_play, |
| 2019 .read_pause = rtsp_read_pause, | 2024 .read_pause = rtsp_read_pause, |
| 2020 }; | 2025 }; |
| 2021 #endif /* CONFIG_RTSP_DEMUXER */ | 2026 #endif /* CONFIG_RTSP_DEMUXER */ |
| 2022 | 2027 |
| 2028 #if CONFIG_SDP_DEMUXER |
| 2023 static int sdp_probe(AVProbeData *p1) | 2029 static int sdp_probe(AVProbeData *p1) |
| 2024 { | 2030 { |
| 2025 const char *p = p1->buf, *p_end = p1->buf + p1->buf_size; | 2031 const char *p = p1->buf, *p_end = p1->buf + p1->buf_size; |
| 2026 | 2032 |
| 2027 /* we look for a line beginning "c=IN IP" */ | 2033 /* we look for a line beginning "c=IN IP" */ |
| 2028 while (p < p_end && *p != '\0') { | 2034 while (p < p_end && *p != '\0') { |
| 2029 if (p + sizeof("c=IN IP") - 1 < p_end && | 2035 if (p + sizeof("c=IN IP") - 1 < p_end && |
| 2030 av_strstart(p, "c=IN IP", NULL)) | 2036 av_strstart(p, "c=IN IP", NULL)) |
| 2031 return AVPROBE_SCORE_MAX / 2; | 2037 return AVPROBE_SCORE_MAX / 2; |
| 2032 | 2038 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2097 | 2103 |
| 2098 AVInputFormat sdp_demuxer = { | 2104 AVInputFormat sdp_demuxer = { |
| 2099 "sdp", | 2105 "sdp", |
| 2100 NULL_IF_CONFIG_SMALL("SDP"), | 2106 NULL_IF_CONFIG_SMALL("SDP"), |
| 2101 sizeof(RTSPState), | 2107 sizeof(RTSPState), |
| 2102 sdp_probe, | 2108 sdp_probe, |
| 2103 sdp_read_header, | 2109 sdp_read_header, |
| 2104 rtsp_fetch_packet, | 2110 rtsp_fetch_packet, |
| 2105 sdp_read_close, | 2111 sdp_read_close, |
| 2106 }; | 2112 }; |
| 2113 #endif /* CONFIG_SDP_DEMUXER */ |
| 2114 |
| 2115 #if CONFIG_RTP_DEMUXER |
| 2116 static int rtp_probe(AVProbeData *p) |
| 2117 { |
| 2118 if (av_strstart(p->filename, "rtp:", NULL)) |
| 2119 return AVPROBE_SCORE_MAX; |
| 2120 return 0; |
| 2121 } |
| 2122 |
| 2123 static int rtp_read_header(AVFormatContext *s, |
| 2124 AVFormatParameters *ap) |
| 2125 { |
| 2126 uint8_t recvbuf[1500]; |
| 2127 char host[500], sdp[500]; |
| 2128 int ret, port; |
| 2129 URLContext* in = NULL; |
| 2130 int payload_type; |
| 2131 AVCodecContext codec; |
| 2132 struct sockaddr_storage addr; |
| 2133 ByteIOContext pb; |
| 2134 socklen_t addrlen = sizeof(addr); |
| 2135 |
| 2136 if (!ff_network_init()) |
| 2137 return AVERROR(EIO); |
| 2138 |
| 2139 ret = url_open(&in, s->filename, URL_RDONLY); |
| 2140 if (ret) |
| 2141 goto fail; |
| 2142 |
| 2143 while (1) { |
| 2144 ret = url_read(in, recvbuf, sizeof(recvbuf)); |
| 2145 if (ret == AVERROR(EAGAIN)) |
| 2146 continue; |
| 2147 if (ret < 0) |
| 2148 goto fail; |
| 2149 if (ret < 12) { |
| 2150 av_log(s, AV_LOG_WARNING, "Received too short packet\n"); |
| 2151 continue; |
| 2152 } |
| 2153 |
| 2154 if ((recvbuf[0] & 0xc0) != 0x80) { |
| 2155 av_log(s, AV_LOG_WARNING, "Unsupported RTP version packet " |
| 2156 "received\n"); |
| 2157 continue; |
| 2158 } |
| 2159 |
| 2160 payload_type = recvbuf[1] & 0x7f; |
| 2161 break; |
| 2162 } |
| 2163 getsockname(url_get_file_handle(in), (struct sockaddr*) &addr, &addrlen); |
| 2164 url_close(in); |
| 2165 in = NULL; |
| 2166 |
| 2167 memset(&codec, 0, sizeof(codec)); |
| 2168 if (ff_rtp_get_codec_info(&codec, payload_type)) { |
| 2169 av_log(s, AV_LOG_ERROR, "Unable to receive RTP payload type %d " |
| 2170 "without an SDP file describing it\n", |
| 2171 payload_type); |
| 2172 goto fail; |
| 2173 } |
| 2174 if (codec.codec_type != AVMEDIA_TYPE_DATA) { |
| 2175 av_log(s, AV_LOG_WARNING, "Guessing on RTP content - if not received " |
| 2176 "properly you need an SDP file " |
| 2177 "describing it\n"); |
| 2178 } |
| 2179 |
| 2180 av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, |
| 2181 NULL, 0, s->filename); |
| 2182 |
| 2183 snprintf(sdp, sizeof(sdp), |
| 2184 "v=0\r\nc=IN IP%d %s\r\nm=%s %d RTP/AVP %d\r\n", |
| 2185 addr.ss_family == AF_INET ? 4 : 6, host, |
| 2186 codec.codec_type == AVMEDIA_TYPE_DATA ? "application" : |
| 2187 codec.codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio", |
| 2188 port, payload_type); |
| 2189 av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp); |
| 2190 |
| 2191 init_put_byte(&pb, sdp, strlen(sdp), 0, NULL, NULL, NULL, NULL); |
| 2192 s->pb = &pb; |
| 2193 |
| 2194 /* sdp_read_header initializes this again */ |
| 2195 ff_network_close(); |
| 2196 |
| 2197 ret = sdp_read_header(s, ap); |
| 2198 s->pb = NULL; |
| 2199 return ret; |
| 2200 |
| 2201 fail: |
| 2202 if (in) |
| 2203 url_close(in); |
| 2204 ff_network_close(); |
| 2205 return ret; |
| 2206 } |
| 2207 |
| 2208 AVInputFormat rtp_demuxer = { |
| 2209 "rtp", |
| 2210 NULL_IF_CONFIG_SMALL("RTP input format"), |
| 2211 sizeof(RTSPState), |
| 2212 rtp_probe, |
| 2213 rtp_read_header, |
| 2214 rtsp_fetch_packet, |
| 2215 sdp_read_close, |
| 2216 .flags = AVFMT_NOFILE, |
| 2217 }; |
| 2218 #endif /* CONFIG_RTP_DEMUXER */ |
| 2219 |
| OLD | NEW |