1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * RTSP/SDP client 3cabdff1aSopenharmony_ci * Copyright (c) 2002 Fabrice Bellard 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "config_components.h" 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 25cabdff1aSopenharmony_ci#include "libavutil/base64.h" 26cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 27cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 28cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 29cabdff1aSopenharmony_ci#include "libavutil/mathematics.h" 30cabdff1aSopenharmony_ci#include "libavutil/parseutils.h" 31cabdff1aSopenharmony_ci#include "libavutil/random_seed.h" 32cabdff1aSopenharmony_ci#include "libavutil/dict.h" 33cabdff1aSopenharmony_ci#include "libavutil/opt.h" 34cabdff1aSopenharmony_ci#include "libavutil/time.h" 35cabdff1aSopenharmony_ci#include "avformat.h" 36cabdff1aSopenharmony_ci#include "avio_internal.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci#if HAVE_POLL_H 39cabdff1aSopenharmony_ci#include <poll.h> 40cabdff1aSopenharmony_ci#endif 41cabdff1aSopenharmony_ci#include "internal.h" 42cabdff1aSopenharmony_ci#include "network.h" 43cabdff1aSopenharmony_ci#include "os_support.h" 44cabdff1aSopenharmony_ci#include "http.h" 45cabdff1aSopenharmony_ci#include "rtsp.h" 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci#include "rtpdec.h" 48cabdff1aSopenharmony_ci#include "rtpproto.h" 49cabdff1aSopenharmony_ci#include "rdt.h" 50cabdff1aSopenharmony_ci#include "rtpdec_formats.h" 51cabdff1aSopenharmony_ci#include "rtpenc_chain.h" 52cabdff1aSopenharmony_ci#include "url.h" 53cabdff1aSopenharmony_ci#include "rtpenc.h" 54cabdff1aSopenharmony_ci#include "mpegts.h" 55cabdff1aSopenharmony_ci#include "version.h" 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci/* Default timeout values for read packet in seconds */ 58cabdff1aSopenharmony_ci#define READ_PACKET_TIMEOUT_S 10 59cabdff1aSopenharmony_ci#define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH 60cabdff1aSopenharmony_ci#define DEFAULT_REORDERING_DELAY 100000 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(RTSPState, x) 63cabdff1aSopenharmony_ci#define DEC AV_OPT_FLAG_DECODING_PARAM 64cabdff1aSopenharmony_ci#define ENC AV_OPT_FLAG_ENCODING_PARAM 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci#define RTSP_FLAG_OPTS(name, longname) \ 67cabdff1aSopenharmony_ci { name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \ 68cabdff1aSopenharmony_ci { "filter_src", "only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" } 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci#define RTSP_MEDIATYPE_OPTS(name, longname) \ 71cabdff1aSopenharmony_ci { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \ 72cabdff1aSopenharmony_ci { "video", "Video", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_VIDEO}, 0, 0, DEC, "allowed_media_types" }, \ 73cabdff1aSopenharmony_ci { "audio", "Audio", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_AUDIO}, 0, 0, DEC, "allowed_media_types" }, \ 74cabdff1aSopenharmony_ci { "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" }, \ 75cabdff1aSopenharmony_ci { "subtitle", "Subtitle", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_SUBTITLE}, 0, 0, DEC, "allowed_media_types" } 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci#define COMMON_OPTS() \ 78cabdff1aSopenharmony_ci { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \ 79cabdff1aSopenharmony_ci { "buffer_size", "Underlying protocol send/receive buffer size", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC }, \ 80cabdff1aSopenharmony_ci { "pkt_size", "Underlying protocol send packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = 1472 }, -1, INT_MAX, ENC } \ 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ciconst AVOption ff_rtsp_options[] = { 84cabdff1aSopenharmony_ci { "initial_pause", "do not start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC }, 85cabdff1aSopenharmony_ci FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags), 86cabdff1aSopenharmony_ci { "rtsp_transport", "set RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \ 87cabdff1aSopenharmony_ci { "udp", "UDP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \ 88cabdff1aSopenharmony_ci { "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \ 89cabdff1aSopenharmony_ci { "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" }, 90cabdff1aSopenharmony_ci { "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" }, 91cabdff1aSopenharmony_ci { "https", "HTTPS tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTPS )}, 0, 0, DEC, "rtsp_transport" }, 92cabdff1aSopenharmony_ci RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"), 93cabdff1aSopenharmony_ci { "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }, 94cabdff1aSopenharmony_ci { "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" }, 95cabdff1aSopenharmony_ci { "satip_raw", "export raw MPEG-TS stream instead of demuxing", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_SATIP_RAW}, 0, 0, DEC, "rtsp_flags" }, 96cabdff1aSopenharmony_ci RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), 97cabdff1aSopenharmony_ci { "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC }, 98cabdff1aSopenharmony_ci { "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC }, 99cabdff1aSopenharmony_ci { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, 100cabdff1aSopenharmony_ci { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT64, {.i64 = 0}, INT_MIN, INT64_MAX, DEC }, 101cabdff1aSopenharmony_ci COMMON_OPTS(), 102cabdff1aSopenharmony_ci { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC }, 103cabdff1aSopenharmony_ci { NULL }, 104cabdff1aSopenharmony_ci}; 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_cistatic const AVOption sdp_options[] = { 107cabdff1aSopenharmony_ci RTSP_FLAG_OPTS("sdp_flags", "SDP flags"), 108cabdff1aSopenharmony_ci { "custom_io", "use custom I/O", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" }, 109cabdff1aSopenharmony_ci { "rtcp_to_source", "send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" }, 110cabdff1aSopenharmony_ci { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections", OFFSET(stimeout), AV_OPT_TYPE_DURATION, {.i64 = READ_PACKET_TIMEOUT_S*1000000}, INT_MIN, INT64_MAX, DEC }, 111cabdff1aSopenharmony_ci { "localaddr", "local address", OFFSET(localaddr),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, \ 112cabdff1aSopenharmony_ci RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), 113cabdff1aSopenharmony_ci COMMON_OPTS(), 114cabdff1aSopenharmony_ci { NULL }, 115cabdff1aSopenharmony_ci}; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_cistatic const AVOption rtp_options[] = { 118cabdff1aSopenharmony_ci RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"), 119cabdff1aSopenharmony_ci { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections", OFFSET(stimeout), AV_OPT_TYPE_DURATION, {.i64 = READ_PACKET_TIMEOUT_S*1000000}, INT_MIN, INT64_MAX, DEC }, 120cabdff1aSopenharmony_ci { "localaddr", "local address", OFFSET(localaddr),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, \ 121cabdff1aSopenharmony_ci RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), 122cabdff1aSopenharmony_ci COMMON_OPTS(), 123cabdff1aSopenharmony_ci { NULL }, 124cabdff1aSopenharmony_ci}; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_cistatic AVDictionary *map_to_opts(RTSPState *rt) 128cabdff1aSopenharmony_ci{ 129cabdff1aSopenharmony_ci AVDictionary *opts = NULL; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci av_dict_set_int(&opts, "buffer_size", rt->buffer_size, 0); 132cabdff1aSopenharmony_ci av_dict_set_int(&opts, "pkt_size", rt->pkt_size, 0); 133cabdff1aSopenharmony_ci if (rt->localaddr && rt->localaddr[0]) 134cabdff1aSopenharmony_ci av_dict_set(&opts, "localaddr", rt->localaddr, 0); 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci return opts; 137cabdff1aSopenharmony_ci} 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_cistatic void get_word_until_chars(char *buf, int buf_size, 140cabdff1aSopenharmony_ci const char *sep, const char **pp) 141cabdff1aSopenharmony_ci{ 142cabdff1aSopenharmony_ci const char *p; 143cabdff1aSopenharmony_ci char *q; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci p = *pp; 146cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 147cabdff1aSopenharmony_ci q = buf; 148cabdff1aSopenharmony_ci while (!strchr(sep, *p) && *p != '\0') { 149cabdff1aSopenharmony_ci if ((q - buf) < buf_size - 1) 150cabdff1aSopenharmony_ci *q++ = *p; 151cabdff1aSopenharmony_ci p++; 152cabdff1aSopenharmony_ci } 153cabdff1aSopenharmony_ci if (buf_size > 0) 154cabdff1aSopenharmony_ci *q = '\0'; 155cabdff1aSopenharmony_ci *pp = p; 156cabdff1aSopenharmony_ci} 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_cistatic void get_word_sep(char *buf, int buf_size, const char *sep, 159cabdff1aSopenharmony_ci const char **pp) 160cabdff1aSopenharmony_ci{ 161cabdff1aSopenharmony_ci if (**pp == '/') (*pp)++; 162cabdff1aSopenharmony_ci get_word_until_chars(buf, buf_size, sep, pp); 163cabdff1aSopenharmony_ci} 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_cistatic void get_word(char *buf, int buf_size, const char **pp) 166cabdff1aSopenharmony_ci{ 167cabdff1aSopenharmony_ci get_word_until_chars(buf, buf_size, SPACE_CHARS, pp); 168cabdff1aSopenharmony_ci} 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci/** Parse a string p in the form of Range:npt=xx-xx, and determine the start 171cabdff1aSopenharmony_ci * and end time. 172cabdff1aSopenharmony_ci * Used for seeking in the rtp stream. 173cabdff1aSopenharmony_ci */ 174cabdff1aSopenharmony_cistatic void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) 175cabdff1aSopenharmony_ci{ 176cabdff1aSopenharmony_ci char buf[256]; 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 179cabdff1aSopenharmony_ci if (!av_stristart(p, "npt=", &p)) 180cabdff1aSopenharmony_ci return; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci *start = AV_NOPTS_VALUE; 183cabdff1aSopenharmony_ci *end = AV_NOPTS_VALUE; 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), "-", &p); 186cabdff1aSopenharmony_ci if (av_parse_time(start, buf, 1) < 0) 187cabdff1aSopenharmony_ci return; 188cabdff1aSopenharmony_ci if (*p == '-') { 189cabdff1aSopenharmony_ci p++; 190cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), "-", &p); 191cabdff1aSopenharmony_ci if (av_parse_time(end, buf, 1) < 0) 192cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_DEBUG, "Failed to parse interval end specification '%s'\n", buf); 193cabdff1aSopenharmony_ci } 194cabdff1aSopenharmony_ci} 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_cistatic int get_sockaddr(AVFormatContext *s, 197cabdff1aSopenharmony_ci const char *buf, struct sockaddr_storage *sock) 198cabdff1aSopenharmony_ci{ 199cabdff1aSopenharmony_ci struct addrinfo hints = { 0 }, *ai = NULL; 200cabdff1aSopenharmony_ci int ret; 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci hints.ai_flags = AI_NUMERICHOST; 203cabdff1aSopenharmony_ci if ((ret = getaddrinfo(buf, NULL, &hints, &ai))) { 204cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "getaddrinfo(%s): %s\n", 205cabdff1aSopenharmony_ci buf, 206cabdff1aSopenharmony_ci gai_strerror(ret)); 207cabdff1aSopenharmony_ci return -1; 208cabdff1aSopenharmony_ci } 209cabdff1aSopenharmony_ci memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen)); 210cabdff1aSopenharmony_ci freeaddrinfo(ai); 211cabdff1aSopenharmony_ci return 0; 212cabdff1aSopenharmony_ci} 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci#if CONFIG_RTPDEC 215cabdff1aSopenharmony_cistatic void init_rtp_handler(const RTPDynamicProtocolHandler *handler, 216cabdff1aSopenharmony_ci RTSPStream *rtsp_st, AVStream *st) 217cabdff1aSopenharmony_ci{ 218cabdff1aSopenharmony_ci AVCodecParameters *par = st ? st->codecpar : NULL; 219cabdff1aSopenharmony_ci if (!handler) 220cabdff1aSopenharmony_ci return; 221cabdff1aSopenharmony_ci if (par) 222cabdff1aSopenharmony_ci par->codec_id = handler->codec_id; 223cabdff1aSopenharmony_ci rtsp_st->dynamic_handler = handler; 224cabdff1aSopenharmony_ci if (st) 225cabdff1aSopenharmony_ci ffstream(st)->need_parsing = handler->need_parsing; 226cabdff1aSopenharmony_ci if (handler->priv_data_size) { 227cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context = av_mallocz(handler->priv_data_size); 228cabdff1aSopenharmony_ci if (!rtsp_st->dynamic_protocol_context) 229cabdff1aSopenharmony_ci rtsp_st->dynamic_handler = NULL; 230cabdff1aSopenharmony_ci } 231cabdff1aSopenharmony_ci} 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_cistatic void finalize_rtp_handler_init(AVFormatContext *s, RTSPStream *rtsp_st, 234cabdff1aSopenharmony_ci AVStream *st) 235cabdff1aSopenharmony_ci{ 236cabdff1aSopenharmony_ci if (rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->init) { 237cabdff1aSopenharmony_ci int ret = rtsp_st->dynamic_handler->init(s, st ? st->index : -1, 238cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context); 239cabdff1aSopenharmony_ci if (ret < 0) { 240cabdff1aSopenharmony_ci if (rtsp_st->dynamic_protocol_context) { 241cabdff1aSopenharmony_ci if (rtsp_st->dynamic_handler->close) 242cabdff1aSopenharmony_ci rtsp_st->dynamic_handler->close( 243cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context); 244cabdff1aSopenharmony_ci av_free(rtsp_st->dynamic_protocol_context); 245cabdff1aSopenharmony_ci } 246cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context = NULL; 247cabdff1aSopenharmony_ci rtsp_st->dynamic_handler = NULL; 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci} 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_ci#if CONFIG_RTSP_DEMUXER 253cabdff1aSopenharmony_cistatic int init_satip_stream(AVFormatContext *s) 254cabdff1aSopenharmony_ci{ 255cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 256cabdff1aSopenharmony_ci RTSPStream *rtsp_st = av_mallocz(sizeof(RTSPStream)); 257cabdff1aSopenharmony_ci if (!rtsp_st) 258cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 259cabdff1aSopenharmony_ci dynarray_add(&rt->rtsp_streams, 260cabdff1aSopenharmony_ci &rt->nb_rtsp_streams, rtsp_st); 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci rtsp_st->sdp_payload_type = 33; // MP2T 263cabdff1aSopenharmony_ci av_strlcpy(rtsp_st->control_url, 264cabdff1aSopenharmony_ci rt->control_uri, sizeof(rtsp_st->control_url)); 265cabdff1aSopenharmony_ci 266cabdff1aSopenharmony_ci if (rt->rtsp_flags & RTSP_FLAG_SATIP_RAW) { 267cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 268cabdff1aSopenharmony_ci if (!st) 269cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 270cabdff1aSopenharmony_ci st->id = rt->nb_rtsp_streams - 1; 271cabdff1aSopenharmony_ci rtsp_st->stream_index = st->index; 272cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_DATA; 273cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS; 274cabdff1aSopenharmony_ci } else { 275cabdff1aSopenharmony_ci rtsp_st->stream_index = -1; 276cabdff1aSopenharmony_ci init_rtp_handler(&ff_mpegts_dynamic_handler, rtsp_st, NULL); 277cabdff1aSopenharmony_ci finalize_rtp_handler_init(s, rtsp_st, NULL); 278cabdff1aSopenharmony_ci } 279cabdff1aSopenharmony_ci return 0; 280cabdff1aSopenharmony_ci} 281cabdff1aSopenharmony_ci#endif 282cabdff1aSopenharmony_ci 283cabdff1aSopenharmony_ci/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */ 284cabdff1aSopenharmony_cistatic int sdp_parse_rtpmap(AVFormatContext *s, 285cabdff1aSopenharmony_ci AVStream *st, RTSPStream *rtsp_st, 286cabdff1aSopenharmony_ci int payload_type, const char *p) 287cabdff1aSopenharmony_ci{ 288cabdff1aSopenharmony_ci AVCodecParameters *par = st->codecpar; 289cabdff1aSopenharmony_ci char buf[256]; 290cabdff1aSopenharmony_ci int i; 291cabdff1aSopenharmony_ci const AVCodecDescriptor *desc; 292cabdff1aSopenharmony_ci const char *c_name; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci /* See if we can handle this kind of payload. 295cabdff1aSopenharmony_ci * The space should normally not be there but some Real streams or 296cabdff1aSopenharmony_ci * particular servers ("RealServer Version 6.1.3.970", see issue 1658) 297cabdff1aSopenharmony_ci * have a trailing space. */ 298cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), "/ ", &p); 299cabdff1aSopenharmony_ci if (payload_type < RTP_PT_PRIVATE) { 300cabdff1aSopenharmony_ci /* We are in a standard case 301cabdff1aSopenharmony_ci * (from http://www.iana.org/assignments/rtp-parameters). */ 302cabdff1aSopenharmony_ci par->codec_id = ff_rtp_codec_id(buf, par->codec_type); 303cabdff1aSopenharmony_ci } 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_NONE) { 306cabdff1aSopenharmony_ci const RTPDynamicProtocolHandler *handler = 307cabdff1aSopenharmony_ci ff_rtp_handler_find_by_name(buf, par->codec_type); 308cabdff1aSopenharmony_ci init_rtp_handler(handler, rtsp_st, st); 309cabdff1aSopenharmony_ci /* If no dynamic handler was found, check with the list of standard 310cabdff1aSopenharmony_ci * allocated types, if such a stream for some reason happens to 311cabdff1aSopenharmony_ci * use a private payload type. This isn't handled in rtpdec.c, since 312cabdff1aSopenharmony_ci * the format name from the rtpmap line never is passed into rtpdec. */ 313cabdff1aSopenharmony_ci if (!rtsp_st->dynamic_handler) 314cabdff1aSopenharmony_ci par->codec_id = ff_rtp_codec_id(buf, par->codec_type); 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci desc = avcodec_descriptor_get(par->codec_id); 318cabdff1aSopenharmony_ci if (desc && desc->name) 319cabdff1aSopenharmony_ci c_name = desc->name; 320cabdff1aSopenharmony_ci else 321cabdff1aSopenharmony_ci c_name = "(null)"; 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), "/", &p); 324cabdff1aSopenharmony_ci i = atoi(buf); 325cabdff1aSopenharmony_ci switch (par->codec_type) { 326cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 327cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "audio codec set to: %s\n", c_name); 328cabdff1aSopenharmony_ci par->sample_rate = RTSP_DEFAULT_AUDIO_SAMPLERATE; 329cabdff1aSopenharmony_ci par->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 330cabdff1aSopenharmony_ci if (i > 0) { 331cabdff1aSopenharmony_ci par->sample_rate = i; 332cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, par->sample_rate); 333cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), "/", &p); 334cabdff1aSopenharmony_ci i = atoi(buf); 335cabdff1aSopenharmony_ci if (i > 0) 336cabdff1aSopenharmony_ci av_channel_layout_default(&par->ch_layout, i); 337cabdff1aSopenharmony_ci } 338cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "audio samplerate set to: %i\n", 339cabdff1aSopenharmony_ci par->sample_rate); 340cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "audio channels set to: %i\n", 341cabdff1aSopenharmony_ci par->ch_layout.nb_channels); 342cabdff1aSopenharmony_ci break; 343cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 344cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "video codec set to: %s\n", c_name); 345cabdff1aSopenharmony_ci if (i > 0) 346cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, i); 347cabdff1aSopenharmony_ci break; 348cabdff1aSopenharmony_ci default: 349cabdff1aSopenharmony_ci break; 350cabdff1aSopenharmony_ci } 351cabdff1aSopenharmony_ci finalize_rtp_handler_init(s, rtsp_st, st); 352cabdff1aSopenharmony_ci return 0; 353cabdff1aSopenharmony_ci} 354cabdff1aSopenharmony_ci 355cabdff1aSopenharmony_ci/* parse the attribute line from the fmtp a line of an sdp response. This 356cabdff1aSopenharmony_ci * is broken out as a function because it is used in rtp_h264.c, which is 357cabdff1aSopenharmony_ci * forthcoming. */ 358cabdff1aSopenharmony_ciint ff_rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, 359cabdff1aSopenharmony_ci char *value, int value_size) 360cabdff1aSopenharmony_ci{ 361cabdff1aSopenharmony_ci *p += strspn(*p, SPACE_CHARS); 362cabdff1aSopenharmony_ci if (**p) { 363cabdff1aSopenharmony_ci get_word_sep(attr, attr_size, "=", p); 364cabdff1aSopenharmony_ci if (**p == '=') 365cabdff1aSopenharmony_ci (*p)++; 366cabdff1aSopenharmony_ci get_word_sep(value, value_size, ";", p); 367cabdff1aSopenharmony_ci if (**p == ';') 368cabdff1aSopenharmony_ci (*p)++; 369cabdff1aSopenharmony_ci return 1; 370cabdff1aSopenharmony_ci } 371cabdff1aSopenharmony_ci return 0; 372cabdff1aSopenharmony_ci} 373cabdff1aSopenharmony_ci 374cabdff1aSopenharmony_citypedef struct SDPParseState { 375cabdff1aSopenharmony_ci /* SDP only */ 376cabdff1aSopenharmony_ci struct sockaddr_storage default_ip; 377cabdff1aSopenharmony_ci int default_ttl; 378cabdff1aSopenharmony_ci int skip_media; ///< set if an unknown m= line occurs 379cabdff1aSopenharmony_ci int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */ 380cabdff1aSopenharmony_ci struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */ 381cabdff1aSopenharmony_ci int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */ 382cabdff1aSopenharmony_ci struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */ 383cabdff1aSopenharmony_ci int seen_rtpmap; 384cabdff1aSopenharmony_ci int seen_fmtp; 385cabdff1aSopenharmony_ci char delayed_fmtp[2048]; 386cabdff1aSopenharmony_ci} SDPParseState; 387cabdff1aSopenharmony_ci 388cabdff1aSopenharmony_cistatic void copy_default_source_addrs(struct RTSPSource **addrs, int count, 389cabdff1aSopenharmony_ci struct RTSPSource ***dest, int *dest_count) 390cabdff1aSopenharmony_ci{ 391cabdff1aSopenharmony_ci RTSPSource *rtsp_src, *rtsp_src2; 392cabdff1aSopenharmony_ci int i; 393cabdff1aSopenharmony_ci for (i = 0; i < count; i++) { 394cabdff1aSopenharmony_ci rtsp_src = addrs[i]; 395cabdff1aSopenharmony_ci rtsp_src2 = av_memdup(rtsp_src, sizeof(*rtsp_src)); 396cabdff1aSopenharmony_ci if (!rtsp_src2) 397cabdff1aSopenharmony_ci continue; 398cabdff1aSopenharmony_ci dynarray_add(dest, dest_count, rtsp_src2); 399cabdff1aSopenharmony_ci } 400cabdff1aSopenharmony_ci} 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_cistatic void parse_fmtp(AVFormatContext *s, RTSPState *rt, 403cabdff1aSopenharmony_ci int payload_type, const char *line) 404cabdff1aSopenharmony_ci{ 405cabdff1aSopenharmony_ci int i; 406cabdff1aSopenharmony_ci 407cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 408cabdff1aSopenharmony_ci RTSPStream *rtsp_st = rt->rtsp_streams[i]; 409cabdff1aSopenharmony_ci if (rtsp_st->sdp_payload_type == payload_type && 410cabdff1aSopenharmony_ci rtsp_st->dynamic_handler && 411cabdff1aSopenharmony_ci rtsp_st->dynamic_handler->parse_sdp_a_line) { 412cabdff1aSopenharmony_ci rtsp_st->dynamic_handler->parse_sdp_a_line(s, rtsp_st->stream_index, 413cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context, line); 414cabdff1aSopenharmony_ci } 415cabdff1aSopenharmony_ci } 416cabdff1aSopenharmony_ci} 417cabdff1aSopenharmony_ci 418cabdff1aSopenharmony_cistatic void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, 419cabdff1aSopenharmony_ci int letter, const char *buf) 420cabdff1aSopenharmony_ci{ 421cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 422cabdff1aSopenharmony_ci char buf1[64], st_type[64]; 423cabdff1aSopenharmony_ci const char *p; 424cabdff1aSopenharmony_ci enum AVMediaType codec_type; 425cabdff1aSopenharmony_ci int payload_type; 426cabdff1aSopenharmony_ci AVStream *st; 427cabdff1aSopenharmony_ci RTSPStream *rtsp_st; 428cabdff1aSopenharmony_ci RTSPSource *rtsp_src; 429cabdff1aSopenharmony_ci struct sockaddr_storage sdp_ip; 430cabdff1aSopenharmony_ci int ttl; 431cabdff1aSopenharmony_ci 432cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "sdp: %c='%s'\n", letter, buf); 433cabdff1aSopenharmony_ci 434cabdff1aSopenharmony_ci p = buf; 435cabdff1aSopenharmony_ci if (s1->skip_media && letter != 'm') 436cabdff1aSopenharmony_ci return; 437cabdff1aSopenharmony_ci switch (letter) { 438cabdff1aSopenharmony_ci case 'c': 439cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 440cabdff1aSopenharmony_ci if (strcmp(buf1, "IN") != 0) 441cabdff1aSopenharmony_ci return; 442cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 443cabdff1aSopenharmony_ci if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6")) 444cabdff1aSopenharmony_ci return; 445cabdff1aSopenharmony_ci get_word_sep(buf1, sizeof(buf1), "/", &p); 446cabdff1aSopenharmony_ci if (get_sockaddr(s, buf1, &sdp_ip)) 447cabdff1aSopenharmony_ci return; 448cabdff1aSopenharmony_ci ttl = 16; 449cabdff1aSopenharmony_ci if (*p == '/') { 450cabdff1aSopenharmony_ci p++; 451cabdff1aSopenharmony_ci get_word_sep(buf1, sizeof(buf1), "/", &p); 452cabdff1aSopenharmony_ci ttl = atoi(buf1); 453cabdff1aSopenharmony_ci } 454cabdff1aSopenharmony_ci if (s->nb_streams == 0) { 455cabdff1aSopenharmony_ci s1->default_ip = sdp_ip; 456cabdff1aSopenharmony_ci s1->default_ttl = ttl; 457cabdff1aSopenharmony_ci } else { 458cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 459cabdff1aSopenharmony_ci rtsp_st->sdp_ip = sdp_ip; 460cabdff1aSopenharmony_ci rtsp_st->sdp_ttl = ttl; 461cabdff1aSopenharmony_ci } 462cabdff1aSopenharmony_ci break; 463cabdff1aSopenharmony_ci case 's': 464cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "title", p, 0); 465cabdff1aSopenharmony_ci break; 466cabdff1aSopenharmony_ci case 'i': 467cabdff1aSopenharmony_ci if (s->nb_streams == 0) { 468cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "comment", p, 0); 469cabdff1aSopenharmony_ci break; 470cabdff1aSopenharmony_ci } 471cabdff1aSopenharmony_ci break; 472cabdff1aSopenharmony_ci case 'm': 473cabdff1aSopenharmony_ci /* new stream */ 474cabdff1aSopenharmony_ci s1->skip_media = 0; 475cabdff1aSopenharmony_ci s1->seen_fmtp = 0; 476cabdff1aSopenharmony_ci s1->seen_rtpmap = 0; 477cabdff1aSopenharmony_ci codec_type = AVMEDIA_TYPE_UNKNOWN; 478cabdff1aSopenharmony_ci get_word(st_type, sizeof(st_type), &p); 479cabdff1aSopenharmony_ci if (!strcmp(st_type, "audio")) { 480cabdff1aSopenharmony_ci codec_type = AVMEDIA_TYPE_AUDIO; 481cabdff1aSopenharmony_ci } else if (!strcmp(st_type, "video")) { 482cabdff1aSopenharmony_ci codec_type = AVMEDIA_TYPE_VIDEO; 483cabdff1aSopenharmony_ci } else if (!strcmp(st_type, "application")) { 484cabdff1aSopenharmony_ci codec_type = AVMEDIA_TYPE_DATA; 485cabdff1aSopenharmony_ci } else if (!strcmp(st_type, "text")) { 486cabdff1aSopenharmony_ci codec_type = AVMEDIA_TYPE_SUBTITLE; 487cabdff1aSopenharmony_ci } 488cabdff1aSopenharmony_ci if (codec_type == AVMEDIA_TYPE_UNKNOWN || 489cabdff1aSopenharmony_ci !(rt->media_type_mask & (1 << codec_type)) || 490cabdff1aSopenharmony_ci rt->nb_rtsp_streams >= s->max_streams 491cabdff1aSopenharmony_ci ) { 492cabdff1aSopenharmony_ci s1->skip_media = 1; 493cabdff1aSopenharmony_ci return; 494cabdff1aSopenharmony_ci } 495cabdff1aSopenharmony_ci rtsp_st = av_mallocz(sizeof(RTSPStream)); 496cabdff1aSopenharmony_ci if (!rtsp_st) 497cabdff1aSopenharmony_ci return; 498cabdff1aSopenharmony_ci rtsp_st->stream_index = -1; 499cabdff1aSopenharmony_ci dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); 500cabdff1aSopenharmony_ci 501cabdff1aSopenharmony_ci rtsp_st->sdp_ip = s1->default_ip; 502cabdff1aSopenharmony_ci rtsp_st->sdp_ttl = s1->default_ttl; 503cabdff1aSopenharmony_ci 504cabdff1aSopenharmony_ci copy_default_source_addrs(s1->default_include_source_addrs, 505cabdff1aSopenharmony_ci s1->nb_default_include_source_addrs, 506cabdff1aSopenharmony_ci &rtsp_st->include_source_addrs, 507cabdff1aSopenharmony_ci &rtsp_st->nb_include_source_addrs); 508cabdff1aSopenharmony_ci copy_default_source_addrs(s1->default_exclude_source_addrs, 509cabdff1aSopenharmony_ci s1->nb_default_exclude_source_addrs, 510cabdff1aSopenharmony_ci &rtsp_st->exclude_source_addrs, 511cabdff1aSopenharmony_ci &rtsp_st->nb_exclude_source_addrs); 512cabdff1aSopenharmony_ci 513cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); /* port */ 514cabdff1aSopenharmony_ci rtsp_st->sdp_port = atoi(buf1); 515cabdff1aSopenharmony_ci 516cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); /* protocol */ 517cabdff1aSopenharmony_ci if (!strcmp(buf1, "udp")) 518cabdff1aSopenharmony_ci rt->transport = RTSP_TRANSPORT_RAW; 519cabdff1aSopenharmony_ci else if (strstr(buf1, "/AVPF") || strstr(buf1, "/SAVPF")) 520cabdff1aSopenharmony_ci rtsp_st->feedback = 1; 521cabdff1aSopenharmony_ci 522cabdff1aSopenharmony_ci /* XXX: handle list of formats */ 523cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); /* format list */ 524cabdff1aSopenharmony_ci rtsp_st->sdp_payload_type = atoi(buf1); 525cabdff1aSopenharmony_ci 526cabdff1aSopenharmony_ci if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { 527cabdff1aSopenharmony_ci /* no corresponding stream */ 528cabdff1aSopenharmony_ci if (rt->transport == RTSP_TRANSPORT_RAW) { 529cabdff1aSopenharmony_ci if (CONFIG_RTPDEC && !rt->ts) 530cabdff1aSopenharmony_ci rt->ts = avpriv_mpegts_parse_open(s); 531cabdff1aSopenharmony_ci } else { 532cabdff1aSopenharmony_ci const RTPDynamicProtocolHandler *handler; 533cabdff1aSopenharmony_ci handler = ff_rtp_handler_find_by_id( 534cabdff1aSopenharmony_ci rtsp_st->sdp_payload_type, AVMEDIA_TYPE_DATA); 535cabdff1aSopenharmony_ci init_rtp_handler(handler, rtsp_st, NULL); 536cabdff1aSopenharmony_ci finalize_rtp_handler_init(s, rtsp_st, NULL); 537cabdff1aSopenharmony_ci } 538cabdff1aSopenharmony_ci } else if (rt->server_type == RTSP_SERVER_WMS && 539cabdff1aSopenharmony_ci codec_type == AVMEDIA_TYPE_DATA) { 540cabdff1aSopenharmony_ci /* RTX stream, a stream that carries all the other actual 541cabdff1aSopenharmony_ci * audio/video streams. Don't expose this to the callers. */ 542cabdff1aSopenharmony_ci } else { 543cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 544cabdff1aSopenharmony_ci if (!st) 545cabdff1aSopenharmony_ci return; 546cabdff1aSopenharmony_ci st->id = rt->nb_rtsp_streams - 1; 547cabdff1aSopenharmony_ci rtsp_st->stream_index = st->index; 548cabdff1aSopenharmony_ci st->codecpar->codec_type = codec_type; 549cabdff1aSopenharmony_ci if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) { 550cabdff1aSopenharmony_ci const RTPDynamicProtocolHandler *handler; 551cabdff1aSopenharmony_ci /* if standard payload type, we can find the codec right now */ 552cabdff1aSopenharmony_ci ff_rtp_get_codec_info(st->codecpar, rtsp_st->sdp_payload_type); 553cabdff1aSopenharmony_ci if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && 554cabdff1aSopenharmony_ci st->codecpar->sample_rate > 0) 555cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, st->codecpar->sample_rate); 556cabdff1aSopenharmony_ci /* Even static payload types may need a custom depacketizer */ 557cabdff1aSopenharmony_ci handler = ff_rtp_handler_find_by_id( 558cabdff1aSopenharmony_ci rtsp_st->sdp_payload_type, st->codecpar->codec_type); 559cabdff1aSopenharmony_ci init_rtp_handler(handler, rtsp_st, st); 560cabdff1aSopenharmony_ci finalize_rtp_handler_init(s, rtsp_st, st); 561cabdff1aSopenharmony_ci } 562cabdff1aSopenharmony_ci if (rt->default_lang[0]) 563cabdff1aSopenharmony_ci av_dict_set(&st->metadata, "language", rt->default_lang, 0); 564cabdff1aSopenharmony_ci } 565cabdff1aSopenharmony_ci /* put a default control url */ 566cabdff1aSopenharmony_ci av_strlcpy(rtsp_st->control_url, rt->control_uri, 567cabdff1aSopenharmony_ci sizeof(rtsp_st->control_url)); 568cabdff1aSopenharmony_ci break; 569cabdff1aSopenharmony_ci case 'a': 570cabdff1aSopenharmony_ci if (av_strstart(p, "control:", &p)) { 571cabdff1aSopenharmony_ci if (rt->nb_rtsp_streams == 0) { 572cabdff1aSopenharmony_ci if (!strncmp(p, "rtsp://", 7)) 573cabdff1aSopenharmony_ci av_strlcpy(rt->control_uri, p, 574cabdff1aSopenharmony_ci sizeof(rt->control_uri)); 575cabdff1aSopenharmony_ci } else { 576cabdff1aSopenharmony_ci char proto[32]; 577cabdff1aSopenharmony_ci /* get the control url */ 578cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 579cabdff1aSopenharmony_ci 580cabdff1aSopenharmony_ci /* XXX: may need to add full url resolution */ 581cabdff1aSopenharmony_ci av_url_split(proto, sizeof(proto), NULL, 0, NULL, 0, 582cabdff1aSopenharmony_ci NULL, NULL, 0, p); 583cabdff1aSopenharmony_ci if (proto[0] == '\0') { 584cabdff1aSopenharmony_ci /* relative control URL */ 585cabdff1aSopenharmony_ci if (rtsp_st->control_url[strlen(rtsp_st->control_url)-1]!='/') 586cabdff1aSopenharmony_ci av_strlcat(rtsp_st->control_url, "/", 587cabdff1aSopenharmony_ci sizeof(rtsp_st->control_url)); 588cabdff1aSopenharmony_ci av_strlcat(rtsp_st->control_url, p, 589cabdff1aSopenharmony_ci sizeof(rtsp_st->control_url)); 590cabdff1aSopenharmony_ci } else 591cabdff1aSopenharmony_ci av_strlcpy(rtsp_st->control_url, p, 592cabdff1aSopenharmony_ci sizeof(rtsp_st->control_url)); 593cabdff1aSopenharmony_ci } 594cabdff1aSopenharmony_ci } else if (av_strstart(p, "rtpmap:", &p) && s->nb_streams > 0) { 595cabdff1aSopenharmony_ci /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ 596cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 597cabdff1aSopenharmony_ci payload_type = atoi(buf1); 598cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 599cabdff1aSopenharmony_ci if (rtsp_st->stream_index >= 0) { 600cabdff1aSopenharmony_ci st = s->streams[rtsp_st->stream_index]; 601cabdff1aSopenharmony_ci sdp_parse_rtpmap(s, st, rtsp_st, payload_type, p); 602cabdff1aSopenharmony_ci } 603cabdff1aSopenharmony_ci s1->seen_rtpmap = 1; 604cabdff1aSopenharmony_ci if (s1->seen_fmtp) { 605cabdff1aSopenharmony_ci parse_fmtp(s, rt, payload_type, s1->delayed_fmtp); 606cabdff1aSopenharmony_ci } 607cabdff1aSopenharmony_ci } else if (av_strstart(p, "fmtp:", &p) || 608cabdff1aSopenharmony_ci av_strstart(p, "framesize:", &p)) { 609cabdff1aSopenharmony_ci // let dynamic protocol handlers have a stab at the line. 610cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 611cabdff1aSopenharmony_ci payload_type = atoi(buf1); 612cabdff1aSopenharmony_ci if (s1->seen_rtpmap) { 613cabdff1aSopenharmony_ci parse_fmtp(s, rt, payload_type, buf); 614cabdff1aSopenharmony_ci } else { 615cabdff1aSopenharmony_ci s1->seen_fmtp = 1; 616cabdff1aSopenharmony_ci av_strlcpy(s1->delayed_fmtp, buf, sizeof(s1->delayed_fmtp)); 617cabdff1aSopenharmony_ci } 618cabdff1aSopenharmony_ci } else if (av_strstart(p, "ssrc:", &p) && s->nb_streams > 0) { 619cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 620cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 621cabdff1aSopenharmony_ci rtsp_st->ssrc = strtoll(buf1, NULL, 10); 622cabdff1aSopenharmony_ci } else if (av_strstart(p, "range:", &p)) { 623cabdff1aSopenharmony_ci int64_t start, end; 624cabdff1aSopenharmony_ci 625cabdff1aSopenharmony_ci // this is so that seeking on a streamed file can work. 626cabdff1aSopenharmony_ci rtsp_parse_range_npt(p, &start, &end); 627cabdff1aSopenharmony_ci s->start_time = start; 628cabdff1aSopenharmony_ci /* AV_NOPTS_VALUE means live broadcast (and can't seek) */ 629cabdff1aSopenharmony_ci s->duration = (end == AV_NOPTS_VALUE) ? 630cabdff1aSopenharmony_ci AV_NOPTS_VALUE : end - start; 631cabdff1aSopenharmony_ci } else if (av_strstart(p, "lang:", &p)) { 632cabdff1aSopenharmony_ci if (s->nb_streams > 0) { 633cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 634cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 635cabdff1aSopenharmony_ci if (rtsp_st->stream_index >= 0) { 636cabdff1aSopenharmony_ci st = s->streams[rtsp_st->stream_index]; 637cabdff1aSopenharmony_ci av_dict_set(&st->metadata, "language", buf1, 0); 638cabdff1aSopenharmony_ci } 639cabdff1aSopenharmony_ci } else 640cabdff1aSopenharmony_ci get_word(rt->default_lang, sizeof(rt->default_lang), &p); 641cabdff1aSopenharmony_ci } else if (av_strstart(p, "IsRealDataType:integer;",&p)) { 642cabdff1aSopenharmony_ci if (atoi(p) == 1) 643cabdff1aSopenharmony_ci rt->transport = RTSP_TRANSPORT_RDT; 644cabdff1aSopenharmony_ci } else if (av_strstart(p, "SampleRate:integer;", &p) && 645cabdff1aSopenharmony_ci s->nb_streams > 0) { 646cabdff1aSopenharmony_ci st = s->streams[s->nb_streams - 1]; 647cabdff1aSopenharmony_ci st->codecpar->sample_rate = atoi(p); 648cabdff1aSopenharmony_ci } else if (av_strstart(p, "crypto:", &p) && s->nb_streams > 0) { 649cabdff1aSopenharmony_ci // RFC 4568 650cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 651cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); // ignore tag 652cabdff1aSopenharmony_ci get_word(rtsp_st->crypto_suite, sizeof(rtsp_st->crypto_suite), &p); 653cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 654cabdff1aSopenharmony_ci if (av_strstart(p, "inline:", &p)) 655cabdff1aSopenharmony_ci get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p); 656cabdff1aSopenharmony_ci } else if (av_strstart(p, "source-filter:", &p)) { 657cabdff1aSopenharmony_ci int exclude = 0; 658cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 659cabdff1aSopenharmony_ci if (strcmp(buf1, "incl") && strcmp(buf1, "excl")) 660cabdff1aSopenharmony_ci return; 661cabdff1aSopenharmony_ci exclude = !strcmp(buf1, "excl"); 662cabdff1aSopenharmony_ci 663cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 664cabdff1aSopenharmony_ci if (strcmp(buf1, "IN") != 0) 665cabdff1aSopenharmony_ci return; 666cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 667cabdff1aSopenharmony_ci if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*")) 668cabdff1aSopenharmony_ci return; 669cabdff1aSopenharmony_ci // not checking that the destination address actually matches or is wildcard 670cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 671cabdff1aSopenharmony_ci 672cabdff1aSopenharmony_ci while (*p != '\0') { 673cabdff1aSopenharmony_ci rtsp_src = av_mallocz(sizeof(*rtsp_src)); 674cabdff1aSopenharmony_ci if (!rtsp_src) 675cabdff1aSopenharmony_ci return; 676cabdff1aSopenharmony_ci get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p); 677cabdff1aSopenharmony_ci if (exclude) { 678cabdff1aSopenharmony_ci if (s->nb_streams == 0) { 679cabdff1aSopenharmony_ci dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src); 680cabdff1aSopenharmony_ci } else { 681cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 682cabdff1aSopenharmony_ci dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src); 683cabdff1aSopenharmony_ci } 684cabdff1aSopenharmony_ci } else { 685cabdff1aSopenharmony_ci if (s->nb_streams == 0) { 686cabdff1aSopenharmony_ci dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src); 687cabdff1aSopenharmony_ci } else { 688cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 689cabdff1aSopenharmony_ci dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src); 690cabdff1aSopenharmony_ci } 691cabdff1aSopenharmony_ci } 692cabdff1aSopenharmony_ci } 693cabdff1aSopenharmony_ci } else { 694cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_WMS) 695cabdff1aSopenharmony_ci ff_wms_parse_sdp_a_line(s, p); 696cabdff1aSopenharmony_ci if (s->nb_streams > 0) { 697cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; 698cabdff1aSopenharmony_ci 699cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_REAL) 700cabdff1aSopenharmony_ci ff_real_parse_sdp_a_line(s, rtsp_st->stream_index, p); 701cabdff1aSopenharmony_ci 702cabdff1aSopenharmony_ci if (rtsp_st->dynamic_handler && 703cabdff1aSopenharmony_ci rtsp_st->dynamic_handler->parse_sdp_a_line) 704cabdff1aSopenharmony_ci rtsp_st->dynamic_handler->parse_sdp_a_line(s, 705cabdff1aSopenharmony_ci rtsp_st->stream_index, 706cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context, buf); 707cabdff1aSopenharmony_ci } 708cabdff1aSopenharmony_ci } 709cabdff1aSopenharmony_ci break; 710cabdff1aSopenharmony_ci } 711cabdff1aSopenharmony_ci} 712cabdff1aSopenharmony_ci 713cabdff1aSopenharmony_ciint ff_sdp_parse(AVFormatContext *s, const char *content) 714cabdff1aSopenharmony_ci{ 715cabdff1aSopenharmony_ci const char *p; 716cabdff1aSopenharmony_ci int letter, i; 717cabdff1aSopenharmony_ci char buf[SDP_MAX_SIZE], *q; 718cabdff1aSopenharmony_ci SDPParseState sdp_parse_state = { { 0 } }, *s1 = &sdp_parse_state; 719cabdff1aSopenharmony_ci 720cabdff1aSopenharmony_ci p = content; 721cabdff1aSopenharmony_ci for (;;) { 722cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 723cabdff1aSopenharmony_ci letter = *p; 724cabdff1aSopenharmony_ci if (letter == '\0') 725cabdff1aSopenharmony_ci break; 726cabdff1aSopenharmony_ci p++; 727cabdff1aSopenharmony_ci if (*p != '=') 728cabdff1aSopenharmony_ci goto next_line; 729cabdff1aSopenharmony_ci p++; 730cabdff1aSopenharmony_ci /* get the content */ 731cabdff1aSopenharmony_ci q = buf; 732cabdff1aSopenharmony_ci while (*p != '\n' && *p != '\r' && *p != '\0') { 733cabdff1aSopenharmony_ci if ((q - buf) < sizeof(buf) - 1) 734cabdff1aSopenharmony_ci *q++ = *p; 735cabdff1aSopenharmony_ci p++; 736cabdff1aSopenharmony_ci } 737cabdff1aSopenharmony_ci *q = '\0'; 738cabdff1aSopenharmony_ci sdp_parse_line(s, s1, letter, buf); 739cabdff1aSopenharmony_ci next_line: 740cabdff1aSopenharmony_ci while (*p != '\n' && *p != '\0') 741cabdff1aSopenharmony_ci p++; 742cabdff1aSopenharmony_ci if (*p == '\n') 743cabdff1aSopenharmony_ci p++; 744cabdff1aSopenharmony_ci } 745cabdff1aSopenharmony_ci 746cabdff1aSopenharmony_ci for (i = 0; i < s1->nb_default_include_source_addrs; i++) 747cabdff1aSopenharmony_ci av_freep(&s1->default_include_source_addrs[i]); 748cabdff1aSopenharmony_ci av_freep(&s1->default_include_source_addrs); 749cabdff1aSopenharmony_ci for (i = 0; i < s1->nb_default_exclude_source_addrs; i++) 750cabdff1aSopenharmony_ci av_freep(&s1->default_exclude_source_addrs[i]); 751cabdff1aSopenharmony_ci av_freep(&s1->default_exclude_source_addrs); 752cabdff1aSopenharmony_ci 753cabdff1aSopenharmony_ci return 0; 754cabdff1aSopenharmony_ci} 755cabdff1aSopenharmony_ci#endif /* CONFIG_RTPDEC */ 756cabdff1aSopenharmony_ci 757cabdff1aSopenharmony_civoid ff_rtsp_undo_setup(AVFormatContext *s, int send_packets) 758cabdff1aSopenharmony_ci{ 759cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 760cabdff1aSopenharmony_ci int i; 761cabdff1aSopenharmony_ci 762cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 763cabdff1aSopenharmony_ci RTSPStream *rtsp_st = rt->rtsp_streams[i]; 764cabdff1aSopenharmony_ci if (!rtsp_st) 765cabdff1aSopenharmony_ci continue; 766cabdff1aSopenharmony_ci if (rtsp_st->transport_priv) { 767cabdff1aSopenharmony_ci if (s->oformat) { 768cabdff1aSopenharmony_ci AVFormatContext *rtpctx = rtsp_st->transport_priv; 769cabdff1aSopenharmony_ci av_write_trailer(rtpctx); 770cabdff1aSopenharmony_ci if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { 771cabdff1aSopenharmony_ci if (CONFIG_RTSP_MUXER && rtpctx->pb && send_packets) 772cabdff1aSopenharmony_ci ff_rtsp_tcp_write_packet(s, rtsp_st); 773cabdff1aSopenharmony_ci ffio_free_dyn_buf(&rtpctx->pb); 774cabdff1aSopenharmony_ci } else { 775cabdff1aSopenharmony_ci avio_closep(&rtpctx->pb); 776cabdff1aSopenharmony_ci } 777cabdff1aSopenharmony_ci avformat_free_context(rtpctx); 778cabdff1aSopenharmony_ci } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT) 779cabdff1aSopenharmony_ci ff_rdt_parse_close(rtsp_st->transport_priv); 780cabdff1aSopenharmony_ci else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RTP) 781cabdff1aSopenharmony_ci ff_rtp_parse_close(rtsp_st->transport_priv); 782cabdff1aSopenharmony_ci } 783cabdff1aSopenharmony_ci rtsp_st->transport_priv = NULL; 784cabdff1aSopenharmony_ci ffurl_closep(&rtsp_st->rtp_handle); 785cabdff1aSopenharmony_ci } 786cabdff1aSopenharmony_ci} 787cabdff1aSopenharmony_ci 788cabdff1aSopenharmony_ci/* close and free RTSP streams */ 789cabdff1aSopenharmony_civoid ff_rtsp_close_streams(AVFormatContext *s) 790cabdff1aSopenharmony_ci{ 791cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 792cabdff1aSopenharmony_ci int i, j; 793cabdff1aSopenharmony_ci RTSPStream *rtsp_st; 794cabdff1aSopenharmony_ci 795cabdff1aSopenharmony_ci ff_rtsp_undo_setup(s, 0); 796cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 797cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[i]; 798cabdff1aSopenharmony_ci if (rtsp_st) { 799cabdff1aSopenharmony_ci if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) { 800cabdff1aSopenharmony_ci if (rtsp_st->dynamic_handler->close) 801cabdff1aSopenharmony_ci rtsp_st->dynamic_handler->close( 802cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context); 803cabdff1aSopenharmony_ci av_free(rtsp_st->dynamic_protocol_context); 804cabdff1aSopenharmony_ci } 805cabdff1aSopenharmony_ci for (j = 0; j < rtsp_st->nb_include_source_addrs; j++) 806cabdff1aSopenharmony_ci av_freep(&rtsp_st->include_source_addrs[j]); 807cabdff1aSopenharmony_ci av_freep(&rtsp_st->include_source_addrs); 808cabdff1aSopenharmony_ci for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++) 809cabdff1aSopenharmony_ci av_freep(&rtsp_st->exclude_source_addrs[j]); 810cabdff1aSopenharmony_ci av_freep(&rtsp_st->exclude_source_addrs); 811cabdff1aSopenharmony_ci 812cabdff1aSopenharmony_ci av_freep(&rtsp_st); 813cabdff1aSopenharmony_ci } 814cabdff1aSopenharmony_ci } 815cabdff1aSopenharmony_ci av_freep(&rt->rtsp_streams); 816cabdff1aSopenharmony_ci if (rt->asf_ctx) { 817cabdff1aSopenharmony_ci avformat_close_input(&rt->asf_ctx); 818cabdff1aSopenharmony_ci } 819cabdff1aSopenharmony_ci if (CONFIG_RTPDEC && rt->ts) 820cabdff1aSopenharmony_ci avpriv_mpegts_parse_close(rt->ts); 821cabdff1aSopenharmony_ci av_freep(&rt->p); 822cabdff1aSopenharmony_ci av_freep(&rt->recvbuf); 823cabdff1aSopenharmony_ci} 824cabdff1aSopenharmony_ci 825cabdff1aSopenharmony_ciint ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) 826cabdff1aSopenharmony_ci{ 827cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 828cabdff1aSopenharmony_ci AVStream *st = NULL; 829cabdff1aSopenharmony_ci int reordering_queue_size = rt->reordering_queue_size; 830cabdff1aSopenharmony_ci if (reordering_queue_size < 0) { 831cabdff1aSopenharmony_ci if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay) 832cabdff1aSopenharmony_ci reordering_queue_size = 0; 833cabdff1aSopenharmony_ci else 834cabdff1aSopenharmony_ci reordering_queue_size = RTP_REORDER_QUEUE_DEFAULT_SIZE; 835cabdff1aSopenharmony_ci } 836cabdff1aSopenharmony_ci 837cabdff1aSopenharmony_ci /* open the RTP context */ 838cabdff1aSopenharmony_ci if (rtsp_st->stream_index >= 0) 839cabdff1aSopenharmony_ci st = s->streams[rtsp_st->stream_index]; 840cabdff1aSopenharmony_ci if (!st) 841cabdff1aSopenharmony_ci s->ctx_flags |= AVFMTCTX_NOHEADER; 842cabdff1aSopenharmony_ci 843cabdff1aSopenharmony_ci if (CONFIG_RTSP_MUXER && s->oformat && st) { 844cabdff1aSopenharmony_ci int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, 845cabdff1aSopenharmony_ci s, st, rtsp_st->rtp_handle, 846cabdff1aSopenharmony_ci rt->pkt_size, 847cabdff1aSopenharmony_ci rtsp_st->stream_index); 848cabdff1aSopenharmony_ci /* Ownership of rtp_handle is passed to the rtp mux context */ 849cabdff1aSopenharmony_ci rtsp_st->rtp_handle = NULL; 850cabdff1aSopenharmony_ci if (ret < 0) 851cabdff1aSopenharmony_ci return ret; 852cabdff1aSopenharmony_ci st->time_base = ((AVFormatContext*)rtsp_st->transport_priv)->streams[0]->time_base; 853cabdff1aSopenharmony_ci } else if (rt->transport == RTSP_TRANSPORT_RAW) { 854cabdff1aSopenharmony_ci return 0; // Don't need to open any parser here 855cabdff1aSopenharmony_ci } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT && st) 856cabdff1aSopenharmony_ci rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, 857cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context, 858cabdff1aSopenharmony_ci rtsp_st->dynamic_handler); 859cabdff1aSopenharmony_ci else if (CONFIG_RTPDEC) 860cabdff1aSopenharmony_ci rtsp_st->transport_priv = ff_rtp_parse_open(s, st, 861cabdff1aSopenharmony_ci rtsp_st->sdp_payload_type, 862cabdff1aSopenharmony_ci reordering_queue_size); 863cabdff1aSopenharmony_ci 864cabdff1aSopenharmony_ci if (!rtsp_st->transport_priv) { 865cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 866cabdff1aSopenharmony_ci } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RTP && 867cabdff1aSopenharmony_ci s->iformat) { 868cabdff1aSopenharmony_ci RTPDemuxContext *rtpctx = rtsp_st->transport_priv; 869cabdff1aSopenharmony_ci rtpctx->ssrc = rtsp_st->ssrc; 870cabdff1aSopenharmony_ci if (rtsp_st->dynamic_handler) { 871cabdff1aSopenharmony_ci ff_rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv, 872cabdff1aSopenharmony_ci rtsp_st->dynamic_protocol_context, 873cabdff1aSopenharmony_ci rtsp_st->dynamic_handler); 874cabdff1aSopenharmony_ci } 875cabdff1aSopenharmony_ci if (rtsp_st->crypto_suite[0]) 876cabdff1aSopenharmony_ci ff_rtp_parse_set_crypto(rtsp_st->transport_priv, 877cabdff1aSopenharmony_ci rtsp_st->crypto_suite, 878cabdff1aSopenharmony_ci rtsp_st->crypto_params); 879cabdff1aSopenharmony_ci } 880cabdff1aSopenharmony_ci 881cabdff1aSopenharmony_ci return 0; 882cabdff1aSopenharmony_ci} 883cabdff1aSopenharmony_ci 884cabdff1aSopenharmony_ci#if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER 885cabdff1aSopenharmony_cistatic void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp) 886cabdff1aSopenharmony_ci{ 887cabdff1aSopenharmony_ci const char *q; 888cabdff1aSopenharmony_ci char *p; 889cabdff1aSopenharmony_ci int v; 890cabdff1aSopenharmony_ci 891cabdff1aSopenharmony_ci q = *pp; 892cabdff1aSopenharmony_ci q += strspn(q, SPACE_CHARS); 893cabdff1aSopenharmony_ci v = strtol(q, &p, 10); 894cabdff1aSopenharmony_ci if (*p == '-') { 895cabdff1aSopenharmony_ci p++; 896cabdff1aSopenharmony_ci *min_ptr = v; 897cabdff1aSopenharmony_ci v = strtol(p, &p, 10); 898cabdff1aSopenharmony_ci *max_ptr = v; 899cabdff1aSopenharmony_ci } else { 900cabdff1aSopenharmony_ci *min_ptr = v; 901cabdff1aSopenharmony_ci *max_ptr = v; 902cabdff1aSopenharmony_ci } 903cabdff1aSopenharmony_ci *pp = p; 904cabdff1aSopenharmony_ci} 905cabdff1aSopenharmony_ci 906cabdff1aSopenharmony_ci/* XXX: only one transport specification is parsed */ 907cabdff1aSopenharmony_cistatic void rtsp_parse_transport(AVFormatContext *s, 908cabdff1aSopenharmony_ci RTSPMessageHeader *reply, const char *p) 909cabdff1aSopenharmony_ci{ 910cabdff1aSopenharmony_ci char transport_protocol[16]; 911cabdff1aSopenharmony_ci char profile[16]; 912cabdff1aSopenharmony_ci char lower_transport[16]; 913cabdff1aSopenharmony_ci char parameter[16]; 914cabdff1aSopenharmony_ci RTSPTransportField *th; 915cabdff1aSopenharmony_ci char buf[256]; 916cabdff1aSopenharmony_ci 917cabdff1aSopenharmony_ci reply->nb_transports = 0; 918cabdff1aSopenharmony_ci 919cabdff1aSopenharmony_ci for (;;) { 920cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 921cabdff1aSopenharmony_ci if (*p == '\0') 922cabdff1aSopenharmony_ci break; 923cabdff1aSopenharmony_ci 924cabdff1aSopenharmony_ci th = &reply->transports[reply->nb_transports]; 925cabdff1aSopenharmony_ci 926cabdff1aSopenharmony_ci get_word_sep(transport_protocol, sizeof(transport_protocol), 927cabdff1aSopenharmony_ci "/", &p); 928cabdff1aSopenharmony_ci if (!av_strcasecmp (transport_protocol, "rtp")) { 929cabdff1aSopenharmony_ci get_word_sep(profile, sizeof(profile), "/;,", &p); 930cabdff1aSopenharmony_ci lower_transport[0] = '\0'; 931cabdff1aSopenharmony_ci /* rtp/avp/<protocol> */ 932cabdff1aSopenharmony_ci if (*p == '/') { 933cabdff1aSopenharmony_ci get_word_sep(lower_transport, sizeof(lower_transport), 934cabdff1aSopenharmony_ci ";,", &p); 935cabdff1aSopenharmony_ci } 936cabdff1aSopenharmony_ci th->transport = RTSP_TRANSPORT_RTP; 937cabdff1aSopenharmony_ci } else if (!av_strcasecmp (transport_protocol, "x-pn-tng") || 938cabdff1aSopenharmony_ci !av_strcasecmp (transport_protocol, "x-real-rdt")) { 939cabdff1aSopenharmony_ci /* x-pn-tng/<protocol> */ 940cabdff1aSopenharmony_ci get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p); 941cabdff1aSopenharmony_ci profile[0] = '\0'; 942cabdff1aSopenharmony_ci th->transport = RTSP_TRANSPORT_RDT; 943cabdff1aSopenharmony_ci } else if (!av_strcasecmp(transport_protocol, "raw")) { 944cabdff1aSopenharmony_ci get_word_sep(profile, sizeof(profile), "/;,", &p); 945cabdff1aSopenharmony_ci lower_transport[0] = '\0'; 946cabdff1aSopenharmony_ci /* raw/raw/<protocol> */ 947cabdff1aSopenharmony_ci if (*p == '/') { 948cabdff1aSopenharmony_ci get_word_sep(lower_transport, sizeof(lower_transport), 949cabdff1aSopenharmony_ci ";,", &p); 950cabdff1aSopenharmony_ci } 951cabdff1aSopenharmony_ci th->transport = RTSP_TRANSPORT_RAW; 952cabdff1aSopenharmony_ci } else { 953cabdff1aSopenharmony_ci break; 954cabdff1aSopenharmony_ci } 955cabdff1aSopenharmony_ci if (!av_strcasecmp(lower_transport, "TCP")) 956cabdff1aSopenharmony_ci th->lower_transport = RTSP_LOWER_TRANSPORT_TCP; 957cabdff1aSopenharmony_ci else 958cabdff1aSopenharmony_ci th->lower_transport = RTSP_LOWER_TRANSPORT_UDP; 959cabdff1aSopenharmony_ci 960cabdff1aSopenharmony_ci if (*p == ';') 961cabdff1aSopenharmony_ci p++; 962cabdff1aSopenharmony_ci /* get each parameter */ 963cabdff1aSopenharmony_ci while (*p != '\0' && *p != ',') { 964cabdff1aSopenharmony_ci get_word_sep(parameter, sizeof(parameter), "=;,", &p); 965cabdff1aSopenharmony_ci if (!strcmp(parameter, "port")) { 966cabdff1aSopenharmony_ci if (*p == '=') { 967cabdff1aSopenharmony_ci p++; 968cabdff1aSopenharmony_ci rtsp_parse_range(&th->port_min, &th->port_max, &p); 969cabdff1aSopenharmony_ci } 970cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "client_port")) { 971cabdff1aSopenharmony_ci if (*p == '=') { 972cabdff1aSopenharmony_ci p++; 973cabdff1aSopenharmony_ci rtsp_parse_range(&th->client_port_min, 974cabdff1aSopenharmony_ci &th->client_port_max, &p); 975cabdff1aSopenharmony_ci } 976cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "server_port")) { 977cabdff1aSopenharmony_ci if (*p == '=') { 978cabdff1aSopenharmony_ci p++; 979cabdff1aSopenharmony_ci rtsp_parse_range(&th->server_port_min, 980cabdff1aSopenharmony_ci &th->server_port_max, &p); 981cabdff1aSopenharmony_ci } 982cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "interleaved")) { 983cabdff1aSopenharmony_ci if (*p == '=') { 984cabdff1aSopenharmony_ci p++; 985cabdff1aSopenharmony_ci rtsp_parse_range(&th->interleaved_min, 986cabdff1aSopenharmony_ci &th->interleaved_max, &p); 987cabdff1aSopenharmony_ci } 988cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "multicast")) { 989cabdff1aSopenharmony_ci if (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP) 990cabdff1aSopenharmony_ci th->lower_transport = RTSP_LOWER_TRANSPORT_UDP_MULTICAST; 991cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "ttl")) { 992cabdff1aSopenharmony_ci if (*p == '=') { 993cabdff1aSopenharmony_ci char *end; 994cabdff1aSopenharmony_ci p++; 995cabdff1aSopenharmony_ci th->ttl = strtol(p, &end, 10); 996cabdff1aSopenharmony_ci p = end; 997cabdff1aSopenharmony_ci } 998cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "destination")) { 999cabdff1aSopenharmony_ci if (*p == '=') { 1000cabdff1aSopenharmony_ci p++; 1001cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), ";,", &p); 1002cabdff1aSopenharmony_ci get_sockaddr(s, buf, &th->destination); 1003cabdff1aSopenharmony_ci } 1004cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "source")) { 1005cabdff1aSopenharmony_ci if (*p == '=') { 1006cabdff1aSopenharmony_ci p++; 1007cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), ";,", &p); 1008cabdff1aSopenharmony_ci av_strlcpy(th->source, buf, sizeof(th->source)); 1009cabdff1aSopenharmony_ci } 1010cabdff1aSopenharmony_ci } else if (!strcmp(parameter, "mode")) { 1011cabdff1aSopenharmony_ci if (*p == '=') { 1012cabdff1aSopenharmony_ci p++; 1013cabdff1aSopenharmony_ci get_word_sep(buf, sizeof(buf), ";, ", &p); 1014cabdff1aSopenharmony_ci if (!strcmp(buf, "record") || 1015cabdff1aSopenharmony_ci !strcmp(buf, "receive")) 1016cabdff1aSopenharmony_ci th->mode_record = 1; 1017cabdff1aSopenharmony_ci } 1018cabdff1aSopenharmony_ci } 1019cabdff1aSopenharmony_ci 1020cabdff1aSopenharmony_ci while (*p != ';' && *p != '\0' && *p != ',') 1021cabdff1aSopenharmony_ci p++; 1022cabdff1aSopenharmony_ci if (*p == ';') 1023cabdff1aSopenharmony_ci p++; 1024cabdff1aSopenharmony_ci } 1025cabdff1aSopenharmony_ci if (*p == ',') 1026cabdff1aSopenharmony_ci p++; 1027cabdff1aSopenharmony_ci 1028cabdff1aSopenharmony_ci reply->nb_transports++; 1029cabdff1aSopenharmony_ci if (reply->nb_transports >= RTSP_MAX_TRANSPORTS) 1030cabdff1aSopenharmony_ci break; 1031cabdff1aSopenharmony_ci } 1032cabdff1aSopenharmony_ci} 1033cabdff1aSopenharmony_ci 1034cabdff1aSopenharmony_cistatic void handle_rtp_info(RTSPState *rt, const char *url, 1035cabdff1aSopenharmony_ci uint32_t seq, uint32_t rtptime) 1036cabdff1aSopenharmony_ci{ 1037cabdff1aSopenharmony_ci int i; 1038cabdff1aSopenharmony_ci if (!rtptime || !url[0]) 1039cabdff1aSopenharmony_ci return; 1040cabdff1aSopenharmony_ci if (rt->transport != RTSP_TRANSPORT_RTP) 1041cabdff1aSopenharmony_ci return; 1042cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 1043cabdff1aSopenharmony_ci RTSPStream *rtsp_st = rt->rtsp_streams[i]; 1044cabdff1aSopenharmony_ci RTPDemuxContext *rtpctx = rtsp_st->transport_priv; 1045cabdff1aSopenharmony_ci if (!rtpctx) 1046cabdff1aSopenharmony_ci continue; 1047cabdff1aSopenharmony_ci if (!strcmp(rtsp_st->control_url, url)) { 1048cabdff1aSopenharmony_ci rtpctx->base_timestamp = rtptime; 1049cabdff1aSopenharmony_ci break; 1050cabdff1aSopenharmony_ci } 1051cabdff1aSopenharmony_ci } 1052cabdff1aSopenharmony_ci} 1053cabdff1aSopenharmony_ci 1054cabdff1aSopenharmony_cistatic void rtsp_parse_rtp_info(RTSPState *rt, const char *p) 1055cabdff1aSopenharmony_ci{ 1056cabdff1aSopenharmony_ci int read = 0; 1057cabdff1aSopenharmony_ci char key[20], value[MAX_URL_SIZE], url[MAX_URL_SIZE] = ""; 1058cabdff1aSopenharmony_ci uint32_t seq = 0, rtptime = 0; 1059cabdff1aSopenharmony_ci 1060cabdff1aSopenharmony_ci for (;;) { 1061cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1062cabdff1aSopenharmony_ci if (!*p) 1063cabdff1aSopenharmony_ci break; 1064cabdff1aSopenharmony_ci get_word_sep(key, sizeof(key), "=", &p); 1065cabdff1aSopenharmony_ci if (*p != '=') 1066cabdff1aSopenharmony_ci break; 1067cabdff1aSopenharmony_ci p++; 1068cabdff1aSopenharmony_ci get_word_sep(value, sizeof(value), ";, ", &p); 1069cabdff1aSopenharmony_ci read++; 1070cabdff1aSopenharmony_ci if (!strcmp(key, "url")) 1071cabdff1aSopenharmony_ci av_strlcpy(url, value, sizeof(url)); 1072cabdff1aSopenharmony_ci else if (!strcmp(key, "seq")) 1073cabdff1aSopenharmony_ci seq = strtoul(value, NULL, 10); 1074cabdff1aSopenharmony_ci else if (!strcmp(key, "rtptime")) 1075cabdff1aSopenharmony_ci rtptime = strtoul(value, NULL, 10); 1076cabdff1aSopenharmony_ci if (*p == ',') { 1077cabdff1aSopenharmony_ci handle_rtp_info(rt, url, seq, rtptime); 1078cabdff1aSopenharmony_ci url[0] = '\0'; 1079cabdff1aSopenharmony_ci seq = rtptime = 0; 1080cabdff1aSopenharmony_ci read = 0; 1081cabdff1aSopenharmony_ci } 1082cabdff1aSopenharmony_ci if (*p) 1083cabdff1aSopenharmony_ci p++; 1084cabdff1aSopenharmony_ci } 1085cabdff1aSopenharmony_ci if (read > 0) 1086cabdff1aSopenharmony_ci handle_rtp_info(rt, url, seq, rtptime); 1087cabdff1aSopenharmony_ci} 1088cabdff1aSopenharmony_ci 1089cabdff1aSopenharmony_civoid ff_rtsp_parse_line(AVFormatContext *s, 1090cabdff1aSopenharmony_ci RTSPMessageHeader *reply, const char *buf, 1091cabdff1aSopenharmony_ci RTSPState *rt, const char *method) 1092cabdff1aSopenharmony_ci{ 1093cabdff1aSopenharmony_ci const char *p; 1094cabdff1aSopenharmony_ci 1095cabdff1aSopenharmony_ci /* NOTE: we do case independent match for broken servers */ 1096cabdff1aSopenharmony_ci p = buf; 1097cabdff1aSopenharmony_ci if (av_stristart(p, "Session:", &p)) { 1098cabdff1aSopenharmony_ci int t; 1099cabdff1aSopenharmony_ci get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); 1100cabdff1aSopenharmony_ci if (av_stristart(p, ";timeout=", &p) && 1101cabdff1aSopenharmony_ci (t = strtol(p, NULL, 10)) > 0) { 1102cabdff1aSopenharmony_ci reply->timeout = t; 1103cabdff1aSopenharmony_ci } 1104cabdff1aSopenharmony_ci } else if (av_stristart(p, "Content-Length:", &p)) { 1105cabdff1aSopenharmony_ci reply->content_length = strtol(p, NULL, 10); 1106cabdff1aSopenharmony_ci } else if (av_stristart(p, "Transport:", &p)) { 1107cabdff1aSopenharmony_ci rtsp_parse_transport(s, reply, p); 1108cabdff1aSopenharmony_ci } else if (av_stristart(p, "CSeq:", &p)) { 1109cabdff1aSopenharmony_ci reply->seq = strtol(p, NULL, 10); 1110cabdff1aSopenharmony_ci } else if (av_stristart(p, "Range:", &p)) { 1111cabdff1aSopenharmony_ci rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end); 1112cabdff1aSopenharmony_ci } else if (av_stristart(p, "RealChallenge1:", &p)) { 1113cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1114cabdff1aSopenharmony_ci av_strlcpy(reply->real_challenge, p, sizeof(reply->real_challenge)); 1115cabdff1aSopenharmony_ci } else if (av_stristart(p, "Server:", &p)) { 1116cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1117cabdff1aSopenharmony_ci av_strlcpy(reply->server, p, sizeof(reply->server)); 1118cabdff1aSopenharmony_ci } else if (av_stristart(p, "Notice:", &p) || 1119cabdff1aSopenharmony_ci av_stristart(p, "X-Notice:", &p)) { 1120cabdff1aSopenharmony_ci reply->notice = strtol(p, NULL, 10); 1121cabdff1aSopenharmony_ci } else if (av_stristart(p, "Location:", &p)) { 1122cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1123cabdff1aSopenharmony_ci av_strlcpy(reply->location, p , sizeof(reply->location)); 1124cabdff1aSopenharmony_ci } else if (av_stristart(p, "WWW-Authenticate:", &p) && rt) { 1125cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1126cabdff1aSopenharmony_ci ff_http_auth_handle_header(&rt->auth_state, "WWW-Authenticate", p); 1127cabdff1aSopenharmony_ci } else if (av_stristart(p, "Authentication-Info:", &p) && rt) { 1128cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1129cabdff1aSopenharmony_ci ff_http_auth_handle_header(&rt->auth_state, "Authentication-Info", p); 1130cabdff1aSopenharmony_ci } else if (av_stristart(p, "Content-Base:", &p) && rt) { 1131cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1132cabdff1aSopenharmony_ci if (method && !strcmp(method, "DESCRIBE")) 1133cabdff1aSopenharmony_ci av_strlcpy(rt->control_uri, p , sizeof(rt->control_uri)); 1134cabdff1aSopenharmony_ci } else if (av_stristart(p, "RTP-Info:", &p) && rt) { 1135cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1136cabdff1aSopenharmony_ci if (method && !strcmp(method, "PLAY")) 1137cabdff1aSopenharmony_ci rtsp_parse_rtp_info(rt, p); 1138cabdff1aSopenharmony_ci } else if (av_stristart(p, "Public:", &p) && rt) { 1139cabdff1aSopenharmony_ci if (strstr(p, "GET_PARAMETER") && 1140cabdff1aSopenharmony_ci method && !strcmp(method, "OPTIONS")) 1141cabdff1aSopenharmony_ci rt->get_parameter_supported = 1; 1142cabdff1aSopenharmony_ci } else if (av_stristart(p, "x-Accept-Dynamic-Rate:", &p) && rt) { 1143cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1144cabdff1aSopenharmony_ci rt->accept_dynamic_rate = atoi(p); 1145cabdff1aSopenharmony_ci } else if (av_stristart(p, "Content-Type:", &p)) { 1146cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1147cabdff1aSopenharmony_ci av_strlcpy(reply->content_type, p, sizeof(reply->content_type)); 1148cabdff1aSopenharmony_ci } else if (av_stristart(p, "com.ses.streamID:", &p)) { 1149cabdff1aSopenharmony_ci p += strspn(p, SPACE_CHARS); 1150cabdff1aSopenharmony_ci av_strlcpy(reply->stream_id, p, sizeof(reply->stream_id)); 1151cabdff1aSopenharmony_ci } 1152cabdff1aSopenharmony_ci} 1153cabdff1aSopenharmony_ci 1154cabdff1aSopenharmony_ci/* skip a RTP/TCP interleaved packet */ 1155cabdff1aSopenharmony_ciint ff_rtsp_skip_packet(AVFormatContext *s) 1156cabdff1aSopenharmony_ci{ 1157cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1158cabdff1aSopenharmony_ci int ret, len, len1; 1159cabdff1aSopenharmony_ci uint8_t buf[MAX_URL_SIZE]; 1160cabdff1aSopenharmony_ci 1161cabdff1aSopenharmony_ci ret = ffurl_read_complete(rt->rtsp_hd, buf, 3); 1162cabdff1aSopenharmony_ci if (ret != 3) 1163cabdff1aSopenharmony_ci return ret < 0 ? ret : AVERROR(EIO); 1164cabdff1aSopenharmony_ci len = AV_RB16(buf + 1); 1165cabdff1aSopenharmony_ci 1166cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "skipping RTP packet len=%d\n", len); 1167cabdff1aSopenharmony_ci 1168cabdff1aSopenharmony_ci /* skip payload */ 1169cabdff1aSopenharmony_ci while (len > 0) { 1170cabdff1aSopenharmony_ci len1 = len; 1171cabdff1aSopenharmony_ci if (len1 > sizeof(buf)) 1172cabdff1aSopenharmony_ci len1 = sizeof(buf); 1173cabdff1aSopenharmony_ci ret = ffurl_read_complete(rt->rtsp_hd, buf, len1); 1174cabdff1aSopenharmony_ci if (ret != len1) 1175cabdff1aSopenharmony_ci return ret < 0 ? ret : AVERROR(EIO); 1176cabdff1aSopenharmony_ci len -= len1; 1177cabdff1aSopenharmony_ci } 1178cabdff1aSopenharmony_ci 1179cabdff1aSopenharmony_ci return 0; 1180cabdff1aSopenharmony_ci} 1181cabdff1aSopenharmony_ci 1182cabdff1aSopenharmony_ciint ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, 1183cabdff1aSopenharmony_ci unsigned char **content_ptr, 1184cabdff1aSopenharmony_ci int return_on_interleaved_data, const char *method) 1185cabdff1aSopenharmony_ci{ 1186cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1187cabdff1aSopenharmony_ci char buf[MAX_URL_SIZE], buf1[MAX_URL_SIZE], *q; 1188cabdff1aSopenharmony_ci unsigned char ch; 1189cabdff1aSopenharmony_ci const char *p; 1190cabdff1aSopenharmony_ci int ret, content_length, line_count, request; 1191cabdff1aSopenharmony_ci unsigned char *content; 1192cabdff1aSopenharmony_ci 1193cabdff1aSopenharmony_cistart: 1194cabdff1aSopenharmony_ci line_count = 0; 1195cabdff1aSopenharmony_ci request = 0; 1196cabdff1aSopenharmony_ci content = NULL; 1197cabdff1aSopenharmony_ci memset(reply, 0, sizeof(*reply)); 1198cabdff1aSopenharmony_ci 1199cabdff1aSopenharmony_ci /* parse reply (XXX: use buffers) */ 1200cabdff1aSopenharmony_ci rt->last_reply[0] = '\0'; 1201cabdff1aSopenharmony_ci for (;;) { 1202cabdff1aSopenharmony_ci q = buf; 1203cabdff1aSopenharmony_ci for (;;) { 1204cabdff1aSopenharmony_ci ret = ffurl_read_complete(rt->rtsp_hd, &ch, 1); 1205cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "ret=%d c=%02x [%c]\n", ret, ch, ch); 1206cabdff1aSopenharmony_ci if (ret != 1) 1207cabdff1aSopenharmony_ci return ret < 0 ? ret : AVERROR(EIO); 1208cabdff1aSopenharmony_ci if (ch == '\n') 1209cabdff1aSopenharmony_ci break; 1210cabdff1aSopenharmony_ci if (ch == '$' && q == buf) { 1211cabdff1aSopenharmony_ci if (return_on_interleaved_data) { 1212cabdff1aSopenharmony_ci return 1; 1213cabdff1aSopenharmony_ci } else { 1214cabdff1aSopenharmony_ci ret = ff_rtsp_skip_packet(s); 1215cabdff1aSopenharmony_ci if (ret < 0) 1216cabdff1aSopenharmony_ci return ret; 1217cabdff1aSopenharmony_ci } 1218cabdff1aSopenharmony_ci } else if (ch != '\r') { 1219cabdff1aSopenharmony_ci if ((q - buf) < sizeof(buf) - 1) 1220cabdff1aSopenharmony_ci *q++ = ch; 1221cabdff1aSopenharmony_ci } 1222cabdff1aSopenharmony_ci } 1223cabdff1aSopenharmony_ci *q = '\0'; 1224cabdff1aSopenharmony_ci 1225cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "line='%s'\n", buf); 1226cabdff1aSopenharmony_ci 1227cabdff1aSopenharmony_ci /* test if last line */ 1228cabdff1aSopenharmony_ci if (buf[0] == '\0') 1229cabdff1aSopenharmony_ci break; 1230cabdff1aSopenharmony_ci p = buf; 1231cabdff1aSopenharmony_ci if (line_count == 0) { 1232cabdff1aSopenharmony_ci /* get reply code */ 1233cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 1234cabdff1aSopenharmony_ci if (!strncmp(buf1, "RTSP/", 5)) { 1235cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); 1236cabdff1aSopenharmony_ci reply->status_code = atoi(buf1); 1237cabdff1aSopenharmony_ci av_strlcpy(reply->reason, p, sizeof(reply->reason)); 1238cabdff1aSopenharmony_ci } else { 1239cabdff1aSopenharmony_ci av_strlcpy(reply->reason, buf1, sizeof(reply->reason)); // method 1240cabdff1aSopenharmony_ci get_word(buf1, sizeof(buf1), &p); // object 1241cabdff1aSopenharmony_ci request = 1; 1242cabdff1aSopenharmony_ci } 1243cabdff1aSopenharmony_ci } else { 1244cabdff1aSopenharmony_ci ff_rtsp_parse_line(s, reply, p, rt, method); 1245cabdff1aSopenharmony_ci av_strlcat(rt->last_reply, p, sizeof(rt->last_reply)); 1246cabdff1aSopenharmony_ci av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply)); 1247cabdff1aSopenharmony_ci } 1248cabdff1aSopenharmony_ci line_count++; 1249cabdff1aSopenharmony_ci } 1250cabdff1aSopenharmony_ci 1251cabdff1aSopenharmony_ci if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0' && !request) 1252cabdff1aSopenharmony_ci av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id)); 1253cabdff1aSopenharmony_ci 1254cabdff1aSopenharmony_ci content_length = reply->content_length; 1255cabdff1aSopenharmony_ci if (content_length > 0) { 1256cabdff1aSopenharmony_ci /* leave some room for a trailing '\0' (useful for simple parsing) */ 1257cabdff1aSopenharmony_ci content = av_malloc(content_length + 1); 1258cabdff1aSopenharmony_ci if (!content) 1259cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1260cabdff1aSopenharmony_ci if ((ret = ffurl_read_complete(rt->rtsp_hd, content, content_length)) != content_length) { 1261cabdff1aSopenharmony_ci av_freep(&content); 1262cabdff1aSopenharmony_ci return ret < 0 ? ret : AVERROR(EIO); 1263cabdff1aSopenharmony_ci } 1264cabdff1aSopenharmony_ci content[content_length] = '\0'; 1265cabdff1aSopenharmony_ci } 1266cabdff1aSopenharmony_ci if (content_ptr) 1267cabdff1aSopenharmony_ci *content_ptr = content; 1268cabdff1aSopenharmony_ci else 1269cabdff1aSopenharmony_ci av_freep(&content); 1270cabdff1aSopenharmony_ci 1271cabdff1aSopenharmony_ci if (request) { 1272cabdff1aSopenharmony_ci char buf[MAX_URL_SIZE]; 1273cabdff1aSopenharmony_ci char base64buf[AV_BASE64_SIZE(sizeof(buf))]; 1274cabdff1aSopenharmony_ci const char* ptr = buf; 1275cabdff1aSopenharmony_ci 1276cabdff1aSopenharmony_ci if (!strcmp(reply->reason, "OPTIONS") || 1277cabdff1aSopenharmony_ci !strcmp(reply->reason, "GET_PARAMETER")) { 1278cabdff1aSopenharmony_ci snprintf(buf, sizeof(buf), "RTSP/1.0 200 OK\r\n"); 1279cabdff1aSopenharmony_ci if (reply->seq) 1280cabdff1aSopenharmony_ci av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", reply->seq); 1281cabdff1aSopenharmony_ci if (reply->session_id[0]) 1282cabdff1aSopenharmony_ci av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", 1283cabdff1aSopenharmony_ci reply->session_id); 1284cabdff1aSopenharmony_ci } else { 1285cabdff1aSopenharmony_ci snprintf(buf, sizeof(buf), "RTSP/1.0 501 Not Implemented\r\n"); 1286cabdff1aSopenharmony_ci } 1287cabdff1aSopenharmony_ci av_strlcat(buf, "\r\n", sizeof(buf)); 1288cabdff1aSopenharmony_ci 1289cabdff1aSopenharmony_ci if (rt->control_transport == RTSP_MODE_TUNNEL) { 1290cabdff1aSopenharmony_ci av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf)); 1291cabdff1aSopenharmony_ci ptr = base64buf; 1292cabdff1aSopenharmony_ci } 1293cabdff1aSopenharmony_ci ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr)); 1294cabdff1aSopenharmony_ci 1295cabdff1aSopenharmony_ci rt->last_cmd_time = av_gettime_relative(); 1296cabdff1aSopenharmony_ci /* Even if the request from the server had data, it is not the data 1297cabdff1aSopenharmony_ci * that the caller wants or expects. The memory could also be leaked 1298cabdff1aSopenharmony_ci * if the actual following reply has content data. */ 1299cabdff1aSopenharmony_ci if (content_ptr) 1300cabdff1aSopenharmony_ci av_freep(content_ptr); 1301cabdff1aSopenharmony_ci /* If method is set, this is called from ff_rtsp_send_cmd, 1302cabdff1aSopenharmony_ci * where a reply to exactly this request is awaited. For 1303cabdff1aSopenharmony_ci * callers from within packet receiving, we just want to 1304cabdff1aSopenharmony_ci * return to the caller and go back to receiving packets. */ 1305cabdff1aSopenharmony_ci if (method) 1306cabdff1aSopenharmony_ci goto start; 1307cabdff1aSopenharmony_ci return 0; 1308cabdff1aSopenharmony_ci } 1309cabdff1aSopenharmony_ci 1310cabdff1aSopenharmony_ci if (rt->seq != reply->seq) { 1311cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n", 1312cabdff1aSopenharmony_ci rt->seq, reply->seq); 1313cabdff1aSopenharmony_ci } 1314cabdff1aSopenharmony_ci 1315cabdff1aSopenharmony_ci /* EOS */ 1316cabdff1aSopenharmony_ci if (reply->notice == 2101 /* End-of-Stream Reached */ || 1317cabdff1aSopenharmony_ci reply->notice == 2104 /* Start-of-Stream Reached */ || 1318cabdff1aSopenharmony_ci reply->notice == 2306 /* Continuous Feed Terminated */) { 1319cabdff1aSopenharmony_ci rt->state = RTSP_STATE_IDLE; 1320cabdff1aSopenharmony_ci } else if (reply->notice >= 4400 && reply->notice < 5500) { 1321cabdff1aSopenharmony_ci return AVERROR(EIO); /* data or server error */ 1322cabdff1aSopenharmony_ci } else if (reply->notice == 2401 /* Ticket Expired */ || 1323cabdff1aSopenharmony_ci (reply->notice >= 5500 && reply->notice < 5600) /* end of term */ ) 1324cabdff1aSopenharmony_ci return AVERROR(EPERM); 1325cabdff1aSopenharmony_ci 1326cabdff1aSopenharmony_ci return 0; 1327cabdff1aSopenharmony_ci} 1328cabdff1aSopenharmony_ci 1329cabdff1aSopenharmony_ci/** 1330cabdff1aSopenharmony_ci * Send a command to the RTSP server without waiting for the reply. 1331cabdff1aSopenharmony_ci * 1332cabdff1aSopenharmony_ci * @param s RTSP (de)muxer context 1333cabdff1aSopenharmony_ci * @param method the method for the request 1334cabdff1aSopenharmony_ci * @param url the target url for the request 1335cabdff1aSopenharmony_ci * @param headers extra header lines to include in the request 1336cabdff1aSopenharmony_ci * @param send_content if non-null, the data to send as request body content 1337cabdff1aSopenharmony_ci * @param send_content_length the length of the send_content data, or 0 if 1338cabdff1aSopenharmony_ci * send_content is null 1339cabdff1aSopenharmony_ci * 1340cabdff1aSopenharmony_ci * @return zero if success, nonzero otherwise 1341cabdff1aSopenharmony_ci */ 1342cabdff1aSopenharmony_cistatic int rtsp_send_cmd_with_content_async(AVFormatContext *s, 1343cabdff1aSopenharmony_ci const char *method, const char *url, 1344cabdff1aSopenharmony_ci const char *headers, 1345cabdff1aSopenharmony_ci const unsigned char *send_content, 1346cabdff1aSopenharmony_ci int send_content_length) 1347cabdff1aSopenharmony_ci{ 1348cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1349cabdff1aSopenharmony_ci char buf[MAX_URL_SIZE], *out_buf; 1350cabdff1aSopenharmony_ci char base64buf[AV_BASE64_SIZE(sizeof(buf))]; 1351cabdff1aSopenharmony_ci 1352cabdff1aSopenharmony_ci if (!rt->rtsp_hd_out) 1353cabdff1aSopenharmony_ci return AVERROR(ENOTCONN); 1354cabdff1aSopenharmony_ci 1355cabdff1aSopenharmony_ci /* Add in RTSP headers */ 1356cabdff1aSopenharmony_ci out_buf = buf; 1357cabdff1aSopenharmony_ci rt->seq++; 1358cabdff1aSopenharmony_ci snprintf(buf, sizeof(buf), "%s %s RTSP/1.0\r\n", method, url); 1359cabdff1aSopenharmony_ci if (headers) 1360cabdff1aSopenharmony_ci av_strlcat(buf, headers, sizeof(buf)); 1361cabdff1aSopenharmony_ci av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq); 1362cabdff1aSopenharmony_ci av_strlcatf(buf, sizeof(buf), "User-Agent: %s\r\n", rt->user_agent); 1363cabdff1aSopenharmony_ci if (rt->session_id[0] != '\0' && (!headers || 1364cabdff1aSopenharmony_ci !strstr(headers, "\nIf-Match:"))) { 1365cabdff1aSopenharmony_ci av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id); 1366cabdff1aSopenharmony_ci } 1367cabdff1aSopenharmony_ci if (rt->auth[0]) { 1368cabdff1aSopenharmony_ci char *str = ff_http_auth_create_response(&rt->auth_state, 1369cabdff1aSopenharmony_ci rt->auth, url, method); 1370cabdff1aSopenharmony_ci if (str) 1371cabdff1aSopenharmony_ci av_strlcat(buf, str, sizeof(buf)); 1372cabdff1aSopenharmony_ci av_free(str); 1373cabdff1aSopenharmony_ci } 1374cabdff1aSopenharmony_ci if (send_content_length > 0 && send_content) 1375cabdff1aSopenharmony_ci av_strlcatf(buf, sizeof(buf), "Content-Length: %d\r\n", send_content_length); 1376cabdff1aSopenharmony_ci av_strlcat(buf, "\r\n", sizeof(buf)); 1377cabdff1aSopenharmony_ci 1378cabdff1aSopenharmony_ci /* base64 encode rtsp if tunneling */ 1379cabdff1aSopenharmony_ci if (rt->control_transport == RTSP_MODE_TUNNEL) { 1380cabdff1aSopenharmony_ci av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf)); 1381cabdff1aSopenharmony_ci out_buf = base64buf; 1382cabdff1aSopenharmony_ci } 1383cabdff1aSopenharmony_ci 1384cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "Sending:\n%s--\n", buf); 1385cabdff1aSopenharmony_ci 1386cabdff1aSopenharmony_ci ffurl_write(rt->rtsp_hd_out, out_buf, strlen(out_buf)); 1387cabdff1aSopenharmony_ci if (send_content_length > 0 && send_content) { 1388cabdff1aSopenharmony_ci if (rt->control_transport == RTSP_MODE_TUNNEL) { 1389cabdff1aSopenharmony_ci avpriv_report_missing_feature(s, "Tunneling of RTSP requests with content data"); 1390cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 1391cabdff1aSopenharmony_ci } 1392cabdff1aSopenharmony_ci ffurl_write(rt->rtsp_hd_out, send_content, send_content_length); 1393cabdff1aSopenharmony_ci } 1394cabdff1aSopenharmony_ci rt->last_cmd_time = av_gettime_relative(); 1395cabdff1aSopenharmony_ci 1396cabdff1aSopenharmony_ci return 0; 1397cabdff1aSopenharmony_ci} 1398cabdff1aSopenharmony_ci 1399cabdff1aSopenharmony_ciint ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method, 1400cabdff1aSopenharmony_ci const char *url, const char *headers) 1401cabdff1aSopenharmony_ci{ 1402cabdff1aSopenharmony_ci return rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0); 1403cabdff1aSopenharmony_ci} 1404cabdff1aSopenharmony_ci 1405cabdff1aSopenharmony_ciint ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url, 1406cabdff1aSopenharmony_ci const char *headers, RTSPMessageHeader *reply, 1407cabdff1aSopenharmony_ci unsigned char **content_ptr) 1408cabdff1aSopenharmony_ci{ 1409cabdff1aSopenharmony_ci return ff_rtsp_send_cmd_with_content(s, method, url, headers, reply, 1410cabdff1aSopenharmony_ci content_ptr, NULL, 0); 1411cabdff1aSopenharmony_ci} 1412cabdff1aSopenharmony_ci 1413cabdff1aSopenharmony_ciint ff_rtsp_send_cmd_with_content(AVFormatContext *s, 1414cabdff1aSopenharmony_ci const char *method, const char *url, 1415cabdff1aSopenharmony_ci const char *header, 1416cabdff1aSopenharmony_ci RTSPMessageHeader *reply, 1417cabdff1aSopenharmony_ci unsigned char **content_ptr, 1418cabdff1aSopenharmony_ci const unsigned char *send_content, 1419cabdff1aSopenharmony_ci int send_content_length) 1420cabdff1aSopenharmony_ci{ 1421cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1422cabdff1aSopenharmony_ci HTTPAuthType cur_auth_type; 1423cabdff1aSopenharmony_ci int ret, attempts = 0; 1424cabdff1aSopenharmony_ci 1425cabdff1aSopenharmony_ciretry: 1426cabdff1aSopenharmony_ci cur_auth_type = rt->auth_state.auth_type; 1427cabdff1aSopenharmony_ci if ((ret = rtsp_send_cmd_with_content_async(s, method, url, header, 1428cabdff1aSopenharmony_ci send_content, 1429cabdff1aSopenharmony_ci send_content_length))) 1430cabdff1aSopenharmony_ci return ret; 1431cabdff1aSopenharmony_ci 1432cabdff1aSopenharmony_ci if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0) 1433cabdff1aSopenharmony_ci return ret; 1434cabdff1aSopenharmony_ci attempts++; 1435cabdff1aSopenharmony_ci 1436cabdff1aSopenharmony_ci if (reply->status_code == 401 && 1437cabdff1aSopenharmony_ci (cur_auth_type == HTTP_AUTH_NONE || rt->auth_state.stale) && 1438cabdff1aSopenharmony_ci rt->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) 1439cabdff1aSopenharmony_ci goto retry; 1440cabdff1aSopenharmony_ci 1441cabdff1aSopenharmony_ci if (reply->status_code > 400){ 1442cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "method %s failed: %d%s\n", 1443cabdff1aSopenharmony_ci method, 1444cabdff1aSopenharmony_ci reply->status_code, 1445cabdff1aSopenharmony_ci reply->reason); 1446cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "%s\n", rt->last_reply); 1447cabdff1aSopenharmony_ci } 1448cabdff1aSopenharmony_ci 1449cabdff1aSopenharmony_ci return 0; 1450cabdff1aSopenharmony_ci} 1451cabdff1aSopenharmony_ci 1452cabdff1aSopenharmony_ciint ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, 1453cabdff1aSopenharmony_ci int lower_transport, const char *real_challenge) 1454cabdff1aSopenharmony_ci{ 1455cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1456cabdff1aSopenharmony_ci int rtx = 0, j, i, err, interleave = 0, port_off = 0; 1457cabdff1aSopenharmony_ci RTSPStream *rtsp_st; 1458cabdff1aSopenharmony_ci RTSPMessageHeader reply1, *reply = &reply1; 1459cabdff1aSopenharmony_ci char cmd[MAX_URL_SIZE]; 1460cabdff1aSopenharmony_ci const char *trans_pref; 1461cabdff1aSopenharmony_ci 1462cabdff1aSopenharmony_ci if (rt->transport == RTSP_TRANSPORT_RDT) 1463cabdff1aSopenharmony_ci trans_pref = "x-pn-tng"; 1464cabdff1aSopenharmony_ci else if (rt->transport == RTSP_TRANSPORT_RAW) 1465cabdff1aSopenharmony_ci trans_pref = "RAW/RAW"; 1466cabdff1aSopenharmony_ci else 1467cabdff1aSopenharmony_ci trans_pref = "RTP/AVP"; 1468cabdff1aSopenharmony_ci 1469cabdff1aSopenharmony_ci /* default timeout: 1 minute */ 1470cabdff1aSopenharmony_ci rt->timeout = 60; 1471cabdff1aSopenharmony_ci 1472cabdff1aSopenharmony_ci /* Choose a random starting offset within the first half of the 1473cabdff1aSopenharmony_ci * port range, to allow for a number of ports to try even if the offset 1474cabdff1aSopenharmony_ci * happens to be at the end of the random range. */ 1475cabdff1aSopenharmony_ci if (rt->rtp_port_max - rt->rtp_port_min >= 4) { 1476cabdff1aSopenharmony_ci port_off = av_get_random_seed() % ((rt->rtp_port_max - rt->rtp_port_min)/2); 1477cabdff1aSopenharmony_ci /* even random offset */ 1478cabdff1aSopenharmony_ci port_off -= port_off & 0x01; 1479cabdff1aSopenharmony_ci } 1480cabdff1aSopenharmony_ci 1481cabdff1aSopenharmony_ci for (j = rt->rtp_port_min + port_off, i = 0; i < rt->nb_rtsp_streams; ++i) { 1482cabdff1aSopenharmony_ci char transport[MAX_URL_SIZE]; 1483cabdff1aSopenharmony_ci 1484cabdff1aSopenharmony_ci /* 1485cabdff1aSopenharmony_ci * WMS serves all UDP data over a single connection, the RTX, which 1486cabdff1aSopenharmony_ci * isn't necessarily the first in the SDP but has to be the first 1487cabdff1aSopenharmony_ci * to be set up, else the second/third SETUP will fail with a 461. 1488cabdff1aSopenharmony_ci */ 1489cabdff1aSopenharmony_ci if (lower_transport == RTSP_LOWER_TRANSPORT_UDP && 1490cabdff1aSopenharmony_ci rt->server_type == RTSP_SERVER_WMS) { 1491cabdff1aSopenharmony_ci if (i == 0) { 1492cabdff1aSopenharmony_ci /* rtx first */ 1493cabdff1aSopenharmony_ci for (rtx = 0; rtx < rt->nb_rtsp_streams; rtx++) { 1494cabdff1aSopenharmony_ci int len = strlen(rt->rtsp_streams[rtx]->control_url); 1495cabdff1aSopenharmony_ci if (len >= 4 && 1496cabdff1aSopenharmony_ci !strcmp(rt->rtsp_streams[rtx]->control_url + len - 4, 1497cabdff1aSopenharmony_ci "/rtx")) 1498cabdff1aSopenharmony_ci break; 1499cabdff1aSopenharmony_ci } 1500cabdff1aSopenharmony_ci if (rtx == rt->nb_rtsp_streams) 1501cabdff1aSopenharmony_ci return -1; /* no RTX found */ 1502cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[rtx]; 1503cabdff1aSopenharmony_ci } else 1504cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1]; 1505cabdff1aSopenharmony_ci } else 1506cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[i]; 1507cabdff1aSopenharmony_ci 1508cabdff1aSopenharmony_ci /* RTP/UDP */ 1509cabdff1aSopenharmony_ci if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) { 1510cabdff1aSopenharmony_ci char buf[256]; 1511cabdff1aSopenharmony_ci 1512cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_WMS && i > 1) { 1513cabdff1aSopenharmony_ci port = reply->transports[0].client_port_min; 1514cabdff1aSopenharmony_ci goto have_port; 1515cabdff1aSopenharmony_ci } 1516cabdff1aSopenharmony_ci 1517cabdff1aSopenharmony_ci /* first try in specified port range */ 1518cabdff1aSopenharmony_ci while (j + 1 <= rt->rtp_port_max) { 1519cabdff1aSopenharmony_ci AVDictionary *opts = map_to_opts(rt); 1520cabdff1aSopenharmony_ci 1521cabdff1aSopenharmony_ci ff_url_join(buf, sizeof(buf), "rtp", NULL, host, -1, 1522cabdff1aSopenharmony_ci "?localport=%d", j); 1523cabdff1aSopenharmony_ci /* we will use two ports per rtp stream (rtp and rtcp) */ 1524cabdff1aSopenharmony_ci j += 2; 1525cabdff1aSopenharmony_ci err = ffurl_open_whitelist(&rtsp_st->rtp_handle, buf, AVIO_FLAG_READ_WRITE, 1526cabdff1aSopenharmony_ci &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); 1527cabdff1aSopenharmony_ci 1528cabdff1aSopenharmony_ci av_dict_free(&opts); 1529cabdff1aSopenharmony_ci 1530cabdff1aSopenharmony_ci if (!err) 1531cabdff1aSopenharmony_ci goto rtp_opened; 1532cabdff1aSopenharmony_ci } 1533cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n"); 1534cabdff1aSopenharmony_ci err = AVERROR(EIO); 1535cabdff1aSopenharmony_ci goto fail; 1536cabdff1aSopenharmony_ci 1537cabdff1aSopenharmony_ci rtp_opened: 1538cabdff1aSopenharmony_ci port = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle); 1539cabdff1aSopenharmony_ci have_port: 1540cabdff1aSopenharmony_ci av_strlcpy(transport, trans_pref, sizeof(transport)); 1541cabdff1aSopenharmony_ci av_strlcat(transport, 1542cabdff1aSopenharmony_ci rt->server_type == RTSP_SERVER_SATIP ? ";" : "/UDP;", 1543cabdff1aSopenharmony_ci sizeof(transport)); 1544cabdff1aSopenharmony_ci if (rt->server_type != RTSP_SERVER_REAL) 1545cabdff1aSopenharmony_ci av_strlcat(transport, "unicast;", sizeof(transport)); 1546cabdff1aSopenharmony_ci av_strlcatf(transport, sizeof(transport), 1547cabdff1aSopenharmony_ci "client_port=%d", port); 1548cabdff1aSopenharmony_ci if (rt->transport == RTSP_TRANSPORT_RTP && 1549cabdff1aSopenharmony_ci !(rt->server_type == RTSP_SERVER_WMS && i > 0)) 1550cabdff1aSopenharmony_ci av_strlcatf(transport, sizeof(transport), "-%d", port + 1); 1551cabdff1aSopenharmony_ci } 1552cabdff1aSopenharmony_ci 1553cabdff1aSopenharmony_ci /* RTP/TCP */ 1554cabdff1aSopenharmony_ci else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) { 1555cabdff1aSopenharmony_ci /* For WMS streams, the application streams are only used for 1556cabdff1aSopenharmony_ci * UDP. When trying to set it up for TCP streams, the server 1557cabdff1aSopenharmony_ci * will return an error. Therefore, we skip those streams. */ 1558cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_WMS && 1559cabdff1aSopenharmony_ci (rtsp_st->stream_index < 0 || 1560cabdff1aSopenharmony_ci s->streams[rtsp_st->stream_index]->codecpar->codec_type == 1561cabdff1aSopenharmony_ci AVMEDIA_TYPE_DATA)) 1562cabdff1aSopenharmony_ci continue; 1563cabdff1aSopenharmony_ci snprintf(transport, sizeof(transport) - 1, 1564cabdff1aSopenharmony_ci "%s/TCP;", trans_pref); 1565cabdff1aSopenharmony_ci if (rt->transport != RTSP_TRANSPORT_RDT) 1566cabdff1aSopenharmony_ci av_strlcat(transport, "unicast;", sizeof(transport)); 1567cabdff1aSopenharmony_ci av_strlcatf(transport, sizeof(transport), 1568cabdff1aSopenharmony_ci "interleaved=%d-%d", 1569cabdff1aSopenharmony_ci interleave, interleave + 1); 1570cabdff1aSopenharmony_ci interleave += 2; 1571cabdff1aSopenharmony_ci } 1572cabdff1aSopenharmony_ci 1573cabdff1aSopenharmony_ci else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) { 1574cabdff1aSopenharmony_ci snprintf(transport, sizeof(transport) - 1, 1575cabdff1aSopenharmony_ci "%s/UDP;multicast", trans_pref); 1576cabdff1aSopenharmony_ci } 1577cabdff1aSopenharmony_ci if (s->oformat) { 1578cabdff1aSopenharmony_ci av_strlcat(transport, ";mode=record", sizeof(transport)); 1579cabdff1aSopenharmony_ci } else if (rt->server_type == RTSP_SERVER_REAL || 1580cabdff1aSopenharmony_ci rt->server_type == RTSP_SERVER_WMS) 1581cabdff1aSopenharmony_ci av_strlcat(transport, ";mode=play", sizeof(transport)); 1582cabdff1aSopenharmony_ci snprintf(cmd, sizeof(cmd), 1583cabdff1aSopenharmony_ci "Transport: %s\r\n", 1584cabdff1aSopenharmony_ci transport); 1585cabdff1aSopenharmony_ci if (rt->accept_dynamic_rate) 1586cabdff1aSopenharmony_ci av_strlcat(cmd, "x-Dynamic-Rate: 0\r\n", sizeof(cmd)); 1587cabdff1aSopenharmony_ci if (CONFIG_RTPDEC && i == 0 && rt->server_type == RTSP_SERVER_REAL) { 1588cabdff1aSopenharmony_ci char real_res[41], real_csum[9]; 1589cabdff1aSopenharmony_ci ff_rdt_calc_response_and_checksum(real_res, real_csum, 1590cabdff1aSopenharmony_ci real_challenge); 1591cabdff1aSopenharmony_ci av_strlcatf(cmd, sizeof(cmd), 1592cabdff1aSopenharmony_ci "If-Match: %s\r\n" 1593cabdff1aSopenharmony_ci "RealChallenge2: %s, sd=%s\r\n", 1594cabdff1aSopenharmony_ci rt->session_id, real_res, real_csum); 1595cabdff1aSopenharmony_ci } 1596cabdff1aSopenharmony_ci ff_rtsp_send_cmd(s, "SETUP", rtsp_st->control_url, cmd, reply, NULL); 1597cabdff1aSopenharmony_ci if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) { 1598cabdff1aSopenharmony_ci err = 1; 1599cabdff1aSopenharmony_ci goto fail; 1600cabdff1aSopenharmony_ci } else if (reply->status_code != RTSP_STATUS_OK || 1601cabdff1aSopenharmony_ci reply->nb_transports != 1) { 1602cabdff1aSopenharmony_ci err = ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); 1603cabdff1aSopenharmony_ci goto fail; 1604cabdff1aSopenharmony_ci } 1605cabdff1aSopenharmony_ci 1606cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_SATIP && reply->stream_id[0]) { 1607cabdff1aSopenharmony_ci char proto[128], host[128], path[512], auth[128]; 1608cabdff1aSopenharmony_ci int port; 1609cabdff1aSopenharmony_ci av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host), 1610cabdff1aSopenharmony_ci &port, path, sizeof(path), rt->control_uri); 1611cabdff1aSopenharmony_ci ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host, 1612cabdff1aSopenharmony_ci port, "/stream=%s", reply->stream_id); 1613cabdff1aSopenharmony_ci } 1614cabdff1aSopenharmony_ci 1615cabdff1aSopenharmony_ci /* XXX: same protocol for all streams is required */ 1616cabdff1aSopenharmony_ci if (i > 0) { 1617cabdff1aSopenharmony_ci if (reply->transports[0].lower_transport != rt->lower_transport || 1618cabdff1aSopenharmony_ci reply->transports[0].transport != rt->transport) { 1619cabdff1aSopenharmony_ci err = AVERROR_INVALIDDATA; 1620cabdff1aSopenharmony_ci goto fail; 1621cabdff1aSopenharmony_ci } 1622cabdff1aSopenharmony_ci } else { 1623cabdff1aSopenharmony_ci rt->lower_transport = reply->transports[0].lower_transport; 1624cabdff1aSopenharmony_ci rt->transport = reply->transports[0].transport; 1625cabdff1aSopenharmony_ci } 1626cabdff1aSopenharmony_ci 1627cabdff1aSopenharmony_ci /* Fail if the server responded with another lower transport mode 1628cabdff1aSopenharmony_ci * than what we requested. */ 1629cabdff1aSopenharmony_ci if (reply->transports[0].lower_transport != lower_transport) { 1630cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Nonmatching transport in server reply\n"); 1631cabdff1aSopenharmony_ci err = AVERROR_INVALIDDATA; 1632cabdff1aSopenharmony_ci goto fail; 1633cabdff1aSopenharmony_ci } 1634cabdff1aSopenharmony_ci 1635cabdff1aSopenharmony_ci switch(reply->transports[0].lower_transport) { 1636cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_TCP: 1637cabdff1aSopenharmony_ci rtsp_st->interleaved_min = reply->transports[0].interleaved_min; 1638cabdff1aSopenharmony_ci rtsp_st->interleaved_max = reply->transports[0].interleaved_max; 1639cabdff1aSopenharmony_ci break; 1640cabdff1aSopenharmony_ci 1641cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_UDP: { 1642cabdff1aSopenharmony_ci char url[MAX_URL_SIZE], options[30] = ""; 1643cabdff1aSopenharmony_ci const char *peer = host; 1644cabdff1aSopenharmony_ci 1645cabdff1aSopenharmony_ci if (rt->rtsp_flags & RTSP_FLAG_FILTER_SRC) 1646cabdff1aSopenharmony_ci av_strlcpy(options, "?connect=1", sizeof(options)); 1647cabdff1aSopenharmony_ci /* Use source address if specified */ 1648cabdff1aSopenharmony_ci if (reply->transports[0].source[0]) 1649cabdff1aSopenharmony_ci peer = reply->transports[0].source; 1650cabdff1aSopenharmony_ci ff_url_join(url, sizeof(url), "rtp", NULL, peer, 1651cabdff1aSopenharmony_ci reply->transports[0].server_port_min, "%s", options); 1652cabdff1aSopenharmony_ci if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && 1653cabdff1aSopenharmony_ci ff_rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { 1654cabdff1aSopenharmony_ci err = AVERROR_INVALIDDATA; 1655cabdff1aSopenharmony_ci goto fail; 1656cabdff1aSopenharmony_ci } 1657cabdff1aSopenharmony_ci break; 1658cabdff1aSopenharmony_ci } 1659cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: { 1660cabdff1aSopenharmony_ci char url[MAX_URL_SIZE], namebuf[50], optbuf[20] = ""; 1661cabdff1aSopenharmony_ci struct sockaddr_storage addr; 1662cabdff1aSopenharmony_ci int port, ttl; 1663cabdff1aSopenharmony_ci AVDictionary *opts = map_to_opts(rt); 1664cabdff1aSopenharmony_ci 1665cabdff1aSopenharmony_ci if (reply->transports[0].destination.ss_family) { 1666cabdff1aSopenharmony_ci addr = reply->transports[0].destination; 1667cabdff1aSopenharmony_ci port = reply->transports[0].port_min; 1668cabdff1aSopenharmony_ci ttl = reply->transports[0].ttl; 1669cabdff1aSopenharmony_ci } else { 1670cabdff1aSopenharmony_ci addr = rtsp_st->sdp_ip; 1671cabdff1aSopenharmony_ci port = rtsp_st->sdp_port; 1672cabdff1aSopenharmony_ci ttl = rtsp_st->sdp_ttl; 1673cabdff1aSopenharmony_ci } 1674cabdff1aSopenharmony_ci if (ttl > 0) 1675cabdff1aSopenharmony_ci snprintf(optbuf, sizeof(optbuf), "?ttl=%d", ttl); 1676cabdff1aSopenharmony_ci getnameinfo((struct sockaddr*) &addr, sizeof(addr), 1677cabdff1aSopenharmony_ci namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); 1678cabdff1aSopenharmony_ci ff_url_join(url, sizeof(url), "rtp", NULL, namebuf, 1679cabdff1aSopenharmony_ci port, "%s", optbuf); 1680cabdff1aSopenharmony_ci err = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, 1681cabdff1aSopenharmony_ci &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); 1682cabdff1aSopenharmony_ci av_dict_free(&opts); 1683cabdff1aSopenharmony_ci 1684cabdff1aSopenharmony_ci if (err < 0) { 1685cabdff1aSopenharmony_ci err = AVERROR_INVALIDDATA; 1686cabdff1aSopenharmony_ci goto fail; 1687cabdff1aSopenharmony_ci } 1688cabdff1aSopenharmony_ci break; 1689cabdff1aSopenharmony_ci } 1690cabdff1aSopenharmony_ci } 1691cabdff1aSopenharmony_ci 1692cabdff1aSopenharmony_ci if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st))) 1693cabdff1aSopenharmony_ci goto fail; 1694cabdff1aSopenharmony_ci } 1695cabdff1aSopenharmony_ci 1696cabdff1aSopenharmony_ci if (rt->nb_rtsp_streams && reply->timeout > 0) 1697cabdff1aSopenharmony_ci rt->timeout = reply->timeout; 1698cabdff1aSopenharmony_ci 1699cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_REAL) 1700cabdff1aSopenharmony_ci rt->need_subscription = 1; 1701cabdff1aSopenharmony_ci 1702cabdff1aSopenharmony_ci return 0; 1703cabdff1aSopenharmony_ci 1704cabdff1aSopenharmony_cifail: 1705cabdff1aSopenharmony_ci ff_rtsp_undo_setup(s, 0); 1706cabdff1aSopenharmony_ci return err; 1707cabdff1aSopenharmony_ci} 1708cabdff1aSopenharmony_ci 1709cabdff1aSopenharmony_civoid ff_rtsp_close_connections(AVFormatContext *s) 1710cabdff1aSopenharmony_ci{ 1711cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1712cabdff1aSopenharmony_ci if (rt->rtsp_hd_out != rt->rtsp_hd) 1713cabdff1aSopenharmony_ci ffurl_closep(&rt->rtsp_hd_out); 1714cabdff1aSopenharmony_ci rt->rtsp_hd_out = NULL; 1715cabdff1aSopenharmony_ci ffurl_closep(&rt->rtsp_hd); 1716cabdff1aSopenharmony_ci} 1717cabdff1aSopenharmony_ci 1718cabdff1aSopenharmony_ciint ff_rtsp_connect(AVFormatContext *s) 1719cabdff1aSopenharmony_ci{ 1720cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 1721cabdff1aSopenharmony_ci char proto[128], host[1024], path[1024]; 1722cabdff1aSopenharmony_ci char tcpname[1024], cmd[MAX_URL_SIZE], auth[128]; 1723cabdff1aSopenharmony_ci const char *lower_rtsp_proto = "tcp"; 1724cabdff1aSopenharmony_ci int port, err, tcp_fd; 1725cabdff1aSopenharmony_ci RTSPMessageHeader reply1, *reply = &reply1; 1726cabdff1aSopenharmony_ci int lower_transport_mask = 0; 1727cabdff1aSopenharmony_ci int default_port = RTSP_DEFAULT_PORT; 1728cabdff1aSopenharmony_ci int https_tunnel = 0; 1729cabdff1aSopenharmony_ci char real_challenge[64] = ""; 1730cabdff1aSopenharmony_ci struct sockaddr_storage peer; 1731cabdff1aSopenharmony_ci socklen_t peer_len = sizeof(peer); 1732cabdff1aSopenharmony_ci 1733cabdff1aSopenharmony_ci if (rt->rtp_port_max < rt->rtp_port_min) { 1734cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Invalid UDP port range, max port %d less " 1735cabdff1aSopenharmony_ci "than min port %d\n", rt->rtp_port_max, 1736cabdff1aSopenharmony_ci rt->rtp_port_min); 1737cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1738cabdff1aSopenharmony_ci } 1739cabdff1aSopenharmony_ci 1740cabdff1aSopenharmony_ci if (!ff_network_init()) 1741cabdff1aSopenharmony_ci return AVERROR(EIO); 1742cabdff1aSopenharmony_ci 1743cabdff1aSopenharmony_ci if (s->max_delay < 0) /* Not set by the caller */ 1744cabdff1aSopenharmony_ci s->max_delay = s->iformat ? DEFAULT_REORDERING_DELAY : 0; 1745cabdff1aSopenharmony_ci 1746cabdff1aSopenharmony_ci rt->control_transport = RTSP_MODE_PLAIN; 1747cabdff1aSopenharmony_ci if (rt->lower_transport_mask & ((1 << RTSP_LOWER_TRANSPORT_HTTP) | 1748cabdff1aSopenharmony_ci (1 << RTSP_LOWER_TRANSPORT_HTTPS))) { 1749cabdff1aSopenharmony_ci https_tunnel = !!(rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_HTTPS)); 1750cabdff1aSopenharmony_ci rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP; 1751cabdff1aSopenharmony_ci rt->control_transport = RTSP_MODE_TUNNEL; 1752cabdff1aSopenharmony_ci } 1753cabdff1aSopenharmony_ci /* Only pass through valid flags from here */ 1754cabdff1aSopenharmony_ci rt->lower_transport_mask &= (1 << RTSP_LOWER_TRANSPORT_NB) - 1; 1755cabdff1aSopenharmony_ci 1756cabdff1aSopenharmony_ciredirect: 1757cabdff1aSopenharmony_ci memset(&reply1, 0, sizeof(reply1)); 1758cabdff1aSopenharmony_ci /* extract hostname and port */ 1759cabdff1aSopenharmony_ci av_url_split(proto, sizeof(proto), auth, sizeof(auth), 1760cabdff1aSopenharmony_ci host, sizeof(host), &port, path, sizeof(path), s->url); 1761cabdff1aSopenharmony_ci 1762cabdff1aSopenharmony_ci if (!strcmp(proto, "rtsps")) { 1763cabdff1aSopenharmony_ci lower_rtsp_proto = "tls"; 1764cabdff1aSopenharmony_ci default_port = RTSPS_DEFAULT_PORT; 1765cabdff1aSopenharmony_ci rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP; 1766cabdff1aSopenharmony_ci } else if (!strcmp(proto, "satip")) { 1767cabdff1aSopenharmony_ci av_strlcpy(proto, "rtsp", sizeof(proto)); 1768cabdff1aSopenharmony_ci rt->server_type = RTSP_SERVER_SATIP; 1769cabdff1aSopenharmony_ci } 1770cabdff1aSopenharmony_ci 1771cabdff1aSopenharmony_ci if (*auth) { 1772cabdff1aSopenharmony_ci av_strlcpy(rt->auth, auth, sizeof(rt->auth)); 1773cabdff1aSopenharmony_ci } 1774cabdff1aSopenharmony_ci if (port < 0) 1775cabdff1aSopenharmony_ci port = default_port; 1776cabdff1aSopenharmony_ci 1777cabdff1aSopenharmony_ci lower_transport_mask = rt->lower_transport_mask; 1778cabdff1aSopenharmony_ci 1779cabdff1aSopenharmony_ci if (!lower_transport_mask) 1780cabdff1aSopenharmony_ci lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1; 1781cabdff1aSopenharmony_ci 1782cabdff1aSopenharmony_ci if (s->oformat) { 1783cabdff1aSopenharmony_ci /* Only UDP or TCP - UDP multicast isn't supported. */ 1784cabdff1aSopenharmony_ci lower_transport_mask &= (1 << RTSP_LOWER_TRANSPORT_UDP) | 1785cabdff1aSopenharmony_ci (1 << RTSP_LOWER_TRANSPORT_TCP); 1786cabdff1aSopenharmony_ci if (!lower_transport_mask || rt->control_transport == RTSP_MODE_TUNNEL) { 1787cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unsupported lower transport method, " 1788cabdff1aSopenharmony_ci "only UDP and TCP are supported for output.\n"); 1789cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 1790cabdff1aSopenharmony_ci goto fail; 1791cabdff1aSopenharmony_ci } 1792cabdff1aSopenharmony_ci } 1793cabdff1aSopenharmony_ci 1794cabdff1aSopenharmony_ci /* Construct the URI used in request; this is similar to s->url, 1795cabdff1aSopenharmony_ci * but with authentication credentials removed and RTSP specific options 1796cabdff1aSopenharmony_ci * stripped out. */ 1797cabdff1aSopenharmony_ci ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, 1798cabdff1aSopenharmony_ci host, port, "%s", path); 1799cabdff1aSopenharmony_ci 1800cabdff1aSopenharmony_ci if (rt->control_transport == RTSP_MODE_TUNNEL) { 1801cabdff1aSopenharmony_ci /* set up initial handshake for tunneling */ 1802cabdff1aSopenharmony_ci char httpname[1024]; 1803cabdff1aSopenharmony_ci char sessioncookie[17]; 1804cabdff1aSopenharmony_ci char headers[1024]; 1805cabdff1aSopenharmony_ci AVDictionary *options = NULL; 1806cabdff1aSopenharmony_ci 1807cabdff1aSopenharmony_ci av_dict_set_int(&options, "timeout", rt->stimeout, 0); 1808cabdff1aSopenharmony_ci 1809cabdff1aSopenharmony_ci ff_url_join(httpname, sizeof(httpname), https_tunnel ? "https" : "http", auth, host, port, "%s", path); 1810cabdff1aSopenharmony_ci snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x", 1811cabdff1aSopenharmony_ci av_get_random_seed(), av_get_random_seed()); 1812cabdff1aSopenharmony_ci 1813cabdff1aSopenharmony_ci /* GET requests */ 1814cabdff1aSopenharmony_ci if (ffurl_alloc(&rt->rtsp_hd, httpname, AVIO_FLAG_READ, 1815cabdff1aSopenharmony_ci &s->interrupt_callback) < 0) { 1816cabdff1aSopenharmony_ci err = AVERROR(EIO); 1817cabdff1aSopenharmony_ci goto fail; 1818cabdff1aSopenharmony_ci } 1819cabdff1aSopenharmony_ci 1820cabdff1aSopenharmony_ci /* generate GET headers */ 1821cabdff1aSopenharmony_ci snprintf(headers, sizeof(headers), 1822cabdff1aSopenharmony_ci "x-sessioncookie: %s\r\n" 1823cabdff1aSopenharmony_ci "Accept: application/x-rtsp-tunnelled\r\n" 1824cabdff1aSopenharmony_ci "Pragma: no-cache\r\n" 1825cabdff1aSopenharmony_ci "Cache-Control: no-cache\r\n", 1826cabdff1aSopenharmony_ci sessioncookie); 1827cabdff1aSopenharmony_ci av_opt_set(rt->rtsp_hd->priv_data, "headers", headers, 0); 1828cabdff1aSopenharmony_ci 1829cabdff1aSopenharmony_ci if (!rt->rtsp_hd->protocol_whitelist && s->protocol_whitelist) { 1830cabdff1aSopenharmony_ci rt->rtsp_hd->protocol_whitelist = av_strdup(s->protocol_whitelist); 1831cabdff1aSopenharmony_ci if (!rt->rtsp_hd->protocol_whitelist) { 1832cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 1833cabdff1aSopenharmony_ci goto fail; 1834cabdff1aSopenharmony_ci } 1835cabdff1aSopenharmony_ci } 1836cabdff1aSopenharmony_ci 1837cabdff1aSopenharmony_ci /* complete the connection */ 1838cabdff1aSopenharmony_ci if (ffurl_connect(rt->rtsp_hd, &options)) { 1839cabdff1aSopenharmony_ci av_dict_free(&options); 1840cabdff1aSopenharmony_ci err = AVERROR(EIO); 1841cabdff1aSopenharmony_ci goto fail; 1842cabdff1aSopenharmony_ci } 1843cabdff1aSopenharmony_ci 1844cabdff1aSopenharmony_ci /* POST requests */ 1845cabdff1aSopenharmony_ci if (ffurl_alloc(&rt->rtsp_hd_out, httpname, AVIO_FLAG_WRITE, 1846cabdff1aSopenharmony_ci &s->interrupt_callback) < 0 ) { 1847cabdff1aSopenharmony_ci err = AVERROR(EIO); 1848cabdff1aSopenharmony_ci goto fail; 1849cabdff1aSopenharmony_ci } 1850cabdff1aSopenharmony_ci 1851cabdff1aSopenharmony_ci /* generate POST headers */ 1852cabdff1aSopenharmony_ci snprintf(headers, sizeof(headers), 1853cabdff1aSopenharmony_ci "x-sessioncookie: %s\r\n" 1854cabdff1aSopenharmony_ci "Content-Type: application/x-rtsp-tunnelled\r\n" 1855cabdff1aSopenharmony_ci "Pragma: no-cache\r\n" 1856cabdff1aSopenharmony_ci "Cache-Control: no-cache\r\n" 1857cabdff1aSopenharmony_ci "Content-Length: 32767\r\n" 1858cabdff1aSopenharmony_ci "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n", 1859cabdff1aSopenharmony_ci sessioncookie); 1860cabdff1aSopenharmony_ci av_opt_set(rt->rtsp_hd_out->priv_data, "headers", headers, 0); 1861cabdff1aSopenharmony_ci av_opt_set(rt->rtsp_hd_out->priv_data, "chunked_post", "0", 0); 1862cabdff1aSopenharmony_ci av_opt_set(rt->rtsp_hd_out->priv_data, "send_expect_100", "0", 0); 1863cabdff1aSopenharmony_ci 1864cabdff1aSopenharmony_ci /* Initialize the authentication state for the POST session. The HTTP 1865cabdff1aSopenharmony_ci * protocol implementation doesn't properly handle multi-pass 1866cabdff1aSopenharmony_ci * authentication for POST requests, since it would require one of 1867cabdff1aSopenharmony_ci * the following: 1868cabdff1aSopenharmony_ci * - implementing Expect: 100-continue, which many HTTP servers 1869cabdff1aSopenharmony_ci * don't support anyway, even less the RTSP servers that do HTTP 1870cabdff1aSopenharmony_ci * tunneling 1871cabdff1aSopenharmony_ci * - sending the whole POST data until getting a 401 reply specifying 1872cabdff1aSopenharmony_ci * what authentication method to use, then resending all that data 1873cabdff1aSopenharmony_ci * - waiting for potential 401 replies directly after sending the 1874cabdff1aSopenharmony_ci * POST header (waiting for some unspecified time) 1875cabdff1aSopenharmony_ci * Therefore, we copy the full auth state, which works for both basic 1876cabdff1aSopenharmony_ci * and digest. (For digest, we would have to synchronize the nonce 1877cabdff1aSopenharmony_ci * count variable between the two sessions, if we'd do more requests 1878cabdff1aSopenharmony_ci * with the original session, though.) 1879cabdff1aSopenharmony_ci */ 1880cabdff1aSopenharmony_ci ff_http_init_auth_state(rt->rtsp_hd_out, rt->rtsp_hd); 1881cabdff1aSopenharmony_ci 1882cabdff1aSopenharmony_ci /* complete the connection */ 1883cabdff1aSopenharmony_ci if (ffurl_connect(rt->rtsp_hd_out, &options)) { 1884cabdff1aSopenharmony_ci av_dict_free(&options); 1885cabdff1aSopenharmony_ci err = AVERROR(EIO); 1886cabdff1aSopenharmony_ci goto fail; 1887cabdff1aSopenharmony_ci } 1888cabdff1aSopenharmony_ci av_dict_free(&options); 1889cabdff1aSopenharmony_ci } else { 1890cabdff1aSopenharmony_ci int ret; 1891cabdff1aSopenharmony_ci /* open the tcp connection */ 1892cabdff1aSopenharmony_ci ff_url_join(tcpname, sizeof(tcpname), lower_rtsp_proto, NULL, 1893cabdff1aSopenharmony_ci host, port, 1894cabdff1aSopenharmony_ci "?timeout=%"PRId64, rt->stimeout); 1895cabdff1aSopenharmony_ci if ((ret = ffurl_open_whitelist(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE, 1896cabdff1aSopenharmony_ci &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL)) < 0) { 1897cabdff1aSopenharmony_ci err = ret; 1898cabdff1aSopenharmony_ci goto fail; 1899cabdff1aSopenharmony_ci } 1900cabdff1aSopenharmony_ci rt->rtsp_hd_out = rt->rtsp_hd; 1901cabdff1aSopenharmony_ci } 1902cabdff1aSopenharmony_ci rt->seq = 0; 1903cabdff1aSopenharmony_ci 1904cabdff1aSopenharmony_ci tcp_fd = ffurl_get_file_handle(rt->rtsp_hd); 1905cabdff1aSopenharmony_ci if (tcp_fd < 0) { 1906cabdff1aSopenharmony_ci err = tcp_fd; 1907cabdff1aSopenharmony_ci goto fail; 1908cabdff1aSopenharmony_ci } 1909cabdff1aSopenharmony_ci if (!getpeername(tcp_fd, (struct sockaddr*) &peer, &peer_len)) { 1910cabdff1aSopenharmony_ci getnameinfo((struct sockaddr*) &peer, peer_len, host, sizeof(host), 1911cabdff1aSopenharmony_ci NULL, 0, NI_NUMERICHOST); 1912cabdff1aSopenharmony_ci } 1913cabdff1aSopenharmony_ci 1914cabdff1aSopenharmony_ci /* request options supported by the server; this also detects server 1915cabdff1aSopenharmony_ci * type */ 1916cabdff1aSopenharmony_ci if (rt->server_type != RTSP_SERVER_SATIP) 1917cabdff1aSopenharmony_ci rt->server_type = RTSP_SERVER_RTP; 1918cabdff1aSopenharmony_ci for (;;) { 1919cabdff1aSopenharmony_ci cmd[0] = 0; 1920cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_REAL) 1921cabdff1aSopenharmony_ci av_strlcat(cmd, 1922cabdff1aSopenharmony_ci /* 1923cabdff1aSopenharmony_ci * The following entries are required for proper 1924cabdff1aSopenharmony_ci * streaming from a Realmedia server. They are 1925cabdff1aSopenharmony_ci * interdependent in some way although we currently 1926cabdff1aSopenharmony_ci * don't quite understand how. Values were copied 1927cabdff1aSopenharmony_ci * from mplayer SVN r23589. 1928cabdff1aSopenharmony_ci * ClientChallenge is a 16-byte ID in hex 1929cabdff1aSopenharmony_ci * CompanyID is a 16-byte ID in base64 1930cabdff1aSopenharmony_ci */ 1931cabdff1aSopenharmony_ci "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n" 1932cabdff1aSopenharmony_ci "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n" 1933cabdff1aSopenharmony_ci "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n" 1934cabdff1aSopenharmony_ci "GUID: 00000000-0000-0000-0000-000000000000\r\n", 1935cabdff1aSopenharmony_ci sizeof(cmd)); 1936cabdff1aSopenharmony_ci ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL); 1937cabdff1aSopenharmony_ci if (reply->status_code != RTSP_STATUS_OK) { 1938cabdff1aSopenharmony_ci err = ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); 1939cabdff1aSopenharmony_ci goto fail; 1940cabdff1aSopenharmony_ci } 1941cabdff1aSopenharmony_ci 1942cabdff1aSopenharmony_ci /* detect server type if not standard-compliant RTP */ 1943cabdff1aSopenharmony_ci if (rt->server_type != RTSP_SERVER_REAL && reply->real_challenge[0]) { 1944cabdff1aSopenharmony_ci rt->server_type = RTSP_SERVER_REAL; 1945cabdff1aSopenharmony_ci continue; 1946cabdff1aSopenharmony_ci } else if (!av_strncasecmp(reply->server, "WMServer/", 9)) { 1947cabdff1aSopenharmony_ci rt->server_type = RTSP_SERVER_WMS; 1948cabdff1aSopenharmony_ci } else if (rt->server_type == RTSP_SERVER_REAL) 1949cabdff1aSopenharmony_ci strcpy(real_challenge, reply->real_challenge); 1950cabdff1aSopenharmony_ci break; 1951cabdff1aSopenharmony_ci } 1952cabdff1aSopenharmony_ci 1953cabdff1aSopenharmony_ci#if CONFIG_RTSP_DEMUXER 1954cabdff1aSopenharmony_ci if (s->iformat) { 1955cabdff1aSopenharmony_ci if (rt->server_type == RTSP_SERVER_SATIP) 1956cabdff1aSopenharmony_ci err = init_satip_stream(s); 1957cabdff1aSopenharmony_ci else 1958cabdff1aSopenharmony_ci err = ff_rtsp_setup_input_streams(s, reply); 1959cabdff1aSopenharmony_ci } else 1960cabdff1aSopenharmony_ci#endif 1961cabdff1aSopenharmony_ci if (CONFIG_RTSP_MUXER) 1962cabdff1aSopenharmony_ci err = ff_rtsp_setup_output_streams(s, host); 1963cabdff1aSopenharmony_ci else 1964cabdff1aSopenharmony_ci av_assert0(0); 1965cabdff1aSopenharmony_ci if (err) 1966cabdff1aSopenharmony_ci goto fail; 1967cabdff1aSopenharmony_ci 1968cabdff1aSopenharmony_ci do { 1969cabdff1aSopenharmony_ci int lower_transport = ff_log2_tab[lower_transport_mask & 1970cabdff1aSopenharmony_ci ~(lower_transport_mask - 1)]; 1971cabdff1aSopenharmony_ci 1972cabdff1aSopenharmony_ci if ((lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) 1973cabdff1aSopenharmony_ci && (rt->rtsp_flags & RTSP_FLAG_PREFER_TCP)) 1974cabdff1aSopenharmony_ci lower_transport = RTSP_LOWER_TRANSPORT_TCP; 1975cabdff1aSopenharmony_ci 1976cabdff1aSopenharmony_ci err = ff_rtsp_make_setup_request(s, host, port, lower_transport, 1977cabdff1aSopenharmony_ci rt->server_type == RTSP_SERVER_REAL ? 1978cabdff1aSopenharmony_ci real_challenge : NULL); 1979cabdff1aSopenharmony_ci if (err < 0) 1980cabdff1aSopenharmony_ci goto fail; 1981cabdff1aSopenharmony_ci lower_transport_mask &= ~(1 << lower_transport); 1982cabdff1aSopenharmony_ci if (lower_transport_mask == 0 && err == 1) { 1983cabdff1aSopenharmony_ci err = AVERROR(EPROTONOSUPPORT); 1984cabdff1aSopenharmony_ci goto fail; 1985cabdff1aSopenharmony_ci } 1986cabdff1aSopenharmony_ci } while (err); 1987cabdff1aSopenharmony_ci 1988cabdff1aSopenharmony_ci rt->lower_transport_mask = lower_transport_mask; 1989cabdff1aSopenharmony_ci av_strlcpy(rt->real_challenge, real_challenge, sizeof(rt->real_challenge)); 1990cabdff1aSopenharmony_ci rt->state = RTSP_STATE_IDLE; 1991cabdff1aSopenharmony_ci rt->seek_timestamp = 0; /* default is to start stream at position zero */ 1992cabdff1aSopenharmony_ci return 0; 1993cabdff1aSopenharmony_ci fail: 1994cabdff1aSopenharmony_ci ff_rtsp_close_streams(s); 1995cabdff1aSopenharmony_ci ff_rtsp_close_connections(s); 1996cabdff1aSopenharmony_ci if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) { 1997cabdff1aSopenharmony_ci char *new_url = av_strdup(reply->location); 1998cabdff1aSopenharmony_ci if (!new_url) { 1999cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 2000cabdff1aSopenharmony_ci goto fail2; 2001cabdff1aSopenharmony_ci } 2002cabdff1aSopenharmony_ci ff_format_set_url(s, new_url); 2003cabdff1aSopenharmony_ci rt->session_id[0] = '\0'; 2004cabdff1aSopenharmony_ci av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", 2005cabdff1aSopenharmony_ci reply->status_code, 2006cabdff1aSopenharmony_ci s->url); 2007cabdff1aSopenharmony_ci goto redirect; 2008cabdff1aSopenharmony_ci } 2009cabdff1aSopenharmony_ci fail2: 2010cabdff1aSopenharmony_ci ff_network_close(); 2011cabdff1aSopenharmony_ci return err; 2012cabdff1aSopenharmony_ci} 2013cabdff1aSopenharmony_ci#endif /* CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER */ 2014cabdff1aSopenharmony_ci 2015cabdff1aSopenharmony_ci#if CONFIG_RTPDEC 2016cabdff1aSopenharmony_ci#if CONFIG_RTSP_DEMUXER 2017cabdff1aSopenharmony_cistatic int parse_rtsp_message(AVFormatContext *s) 2018cabdff1aSopenharmony_ci{ 2019cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2020cabdff1aSopenharmony_ci int ret; 2021cabdff1aSopenharmony_ci 2022cabdff1aSopenharmony_ci if (rt->rtsp_flags & RTSP_FLAG_LISTEN) { 2023cabdff1aSopenharmony_ci if (rt->state == RTSP_STATE_STREAMING) { 2024cabdff1aSopenharmony_ci return ff_rtsp_parse_streaming_commands(s); 2025cabdff1aSopenharmony_ci } else 2026cabdff1aSopenharmony_ci return AVERROR_EOF; 2027cabdff1aSopenharmony_ci } else { 2028cabdff1aSopenharmony_ci RTSPMessageHeader reply; 2029cabdff1aSopenharmony_ci ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL); 2030cabdff1aSopenharmony_ci if (ret < 0) 2031cabdff1aSopenharmony_ci return ret; 2032cabdff1aSopenharmony_ci /* XXX: parse message */ 2033cabdff1aSopenharmony_ci if (rt->state != RTSP_STATE_STREAMING) 2034cabdff1aSopenharmony_ci return 0; 2035cabdff1aSopenharmony_ci } 2036cabdff1aSopenharmony_ci 2037cabdff1aSopenharmony_ci return 0; 2038cabdff1aSopenharmony_ci} 2039cabdff1aSopenharmony_ci#endif 2040cabdff1aSopenharmony_ci 2041cabdff1aSopenharmony_cistatic int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, 2042cabdff1aSopenharmony_ci uint8_t *buf, int buf_size, int64_t wait_end) 2043cabdff1aSopenharmony_ci{ 2044cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2045cabdff1aSopenharmony_ci RTSPStream *rtsp_st; 2046cabdff1aSopenharmony_ci int n, i, ret; 2047cabdff1aSopenharmony_ci struct pollfd *p = rt->p; 2048cabdff1aSopenharmony_ci int *fds = NULL, fdsnum, fdsidx; 2049cabdff1aSopenharmony_ci int64_t runs = rt->stimeout / POLLING_TIME / 1000; 2050cabdff1aSopenharmony_ci 2051cabdff1aSopenharmony_ci if (!p) { 2052cabdff1aSopenharmony_ci p = rt->p = av_malloc_array(2 * rt->nb_rtsp_streams + 1, sizeof(*p)); 2053cabdff1aSopenharmony_ci if (!p) 2054cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2055cabdff1aSopenharmony_ci 2056cabdff1aSopenharmony_ci if (rt->rtsp_hd) { 2057cabdff1aSopenharmony_ci p[rt->max_p].fd = ffurl_get_file_handle(rt->rtsp_hd); 2058cabdff1aSopenharmony_ci p[rt->max_p++].events = POLLIN; 2059cabdff1aSopenharmony_ci } 2060cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2061cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[i]; 2062cabdff1aSopenharmony_ci if (rtsp_st->rtp_handle) { 2063cabdff1aSopenharmony_ci if (ret = ffurl_get_multi_file_handle(rtsp_st->rtp_handle, 2064cabdff1aSopenharmony_ci &fds, &fdsnum)) { 2065cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to recover rtp ports\n"); 2066cabdff1aSopenharmony_ci return ret; 2067cabdff1aSopenharmony_ci } 2068cabdff1aSopenharmony_ci if (fdsnum != 2) { 2069cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 2070cabdff1aSopenharmony_ci "Number of fds %d not supported\n", fdsnum); 2071cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 2072cabdff1aSopenharmony_ci } 2073cabdff1aSopenharmony_ci for (fdsidx = 0; fdsidx < fdsnum; fdsidx++) { 2074cabdff1aSopenharmony_ci p[rt->max_p].fd = fds[fdsidx]; 2075cabdff1aSopenharmony_ci p[rt->max_p++].events = POLLIN; 2076cabdff1aSopenharmony_ci } 2077cabdff1aSopenharmony_ci av_freep(&fds); 2078cabdff1aSopenharmony_ci } 2079cabdff1aSopenharmony_ci } 2080cabdff1aSopenharmony_ci } 2081cabdff1aSopenharmony_ci 2082cabdff1aSopenharmony_ci for (;;) { 2083cabdff1aSopenharmony_ci if (ff_check_interrupt(&s->interrupt_callback)) 2084cabdff1aSopenharmony_ci return AVERROR_EXIT; 2085cabdff1aSopenharmony_ci if (wait_end && wait_end - av_gettime_relative() < 0) 2086cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 2087cabdff1aSopenharmony_ci n = poll(p, rt->max_p, POLLING_TIME); 2088cabdff1aSopenharmony_ci if (n > 0) { 2089cabdff1aSopenharmony_ci int j = rt->rtsp_hd ? 1 : 0; 2090cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2091cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[i]; 2092cabdff1aSopenharmony_ci if (rtsp_st->rtp_handle) { 2093cabdff1aSopenharmony_ci if (p[j].revents & POLLIN || p[j+1].revents & POLLIN) { 2094cabdff1aSopenharmony_ci ret = ffurl_read(rtsp_st->rtp_handle, buf, buf_size); 2095cabdff1aSopenharmony_ci if (ret > 0) { 2096cabdff1aSopenharmony_ci *prtsp_st = rtsp_st; 2097cabdff1aSopenharmony_ci return ret; 2098cabdff1aSopenharmony_ci } 2099cabdff1aSopenharmony_ci } 2100cabdff1aSopenharmony_ci j+=2; 2101cabdff1aSopenharmony_ci } 2102cabdff1aSopenharmony_ci } 2103cabdff1aSopenharmony_ci#if CONFIG_RTSP_DEMUXER 2104cabdff1aSopenharmony_ci if (rt->rtsp_hd && p[0].revents & POLLIN) { 2105cabdff1aSopenharmony_ci if ((ret = parse_rtsp_message(s)) < 0) { 2106cabdff1aSopenharmony_ci return ret; 2107cabdff1aSopenharmony_ci } 2108cabdff1aSopenharmony_ci } 2109cabdff1aSopenharmony_ci#endif 2110cabdff1aSopenharmony_ci } else if (n == 0 && rt->stimeout > 0 && --runs <= 0) { 2111cabdff1aSopenharmony_ci return AVERROR(ETIMEDOUT); 2112cabdff1aSopenharmony_ci } else if (n < 0 && errno != EINTR) 2113cabdff1aSopenharmony_ci return AVERROR(errno); 2114cabdff1aSopenharmony_ci } 2115cabdff1aSopenharmony_ci} 2116cabdff1aSopenharmony_ci 2117cabdff1aSopenharmony_cistatic int pick_stream(AVFormatContext *s, RTSPStream **rtsp_st, 2118cabdff1aSopenharmony_ci const uint8_t *buf, int len) 2119cabdff1aSopenharmony_ci{ 2120cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2121cabdff1aSopenharmony_ci int i; 2122cabdff1aSopenharmony_ci if (len < 0) 2123cabdff1aSopenharmony_ci return len; 2124cabdff1aSopenharmony_ci if (rt->nb_rtsp_streams == 1) { 2125cabdff1aSopenharmony_ci *rtsp_st = rt->rtsp_streams[0]; 2126cabdff1aSopenharmony_ci return len; 2127cabdff1aSopenharmony_ci } 2128cabdff1aSopenharmony_ci if (len >= 8 && rt->transport == RTSP_TRANSPORT_RTP) { 2129cabdff1aSopenharmony_ci if (RTP_PT_IS_RTCP(rt->recvbuf[1])) { 2130cabdff1aSopenharmony_ci int no_ssrc = 0; 2131cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2132cabdff1aSopenharmony_ci RTPDemuxContext *rtpctx = rt->rtsp_streams[i]->transport_priv; 2133cabdff1aSopenharmony_ci if (!rtpctx) 2134cabdff1aSopenharmony_ci continue; 2135cabdff1aSopenharmony_ci if (rtpctx->ssrc == AV_RB32(&buf[4])) { 2136cabdff1aSopenharmony_ci *rtsp_st = rt->rtsp_streams[i]; 2137cabdff1aSopenharmony_ci return len; 2138cabdff1aSopenharmony_ci } 2139cabdff1aSopenharmony_ci if (!rtpctx->ssrc) 2140cabdff1aSopenharmony_ci no_ssrc = 1; 2141cabdff1aSopenharmony_ci } 2142cabdff1aSopenharmony_ci if (no_ssrc) { 2143cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, 2144cabdff1aSopenharmony_ci "Unable to pick stream for packet - SSRC not known for " 2145cabdff1aSopenharmony_ci "all streams\n"); 2146cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 2147cabdff1aSopenharmony_ci } 2148cabdff1aSopenharmony_ci } else { 2149cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2150cabdff1aSopenharmony_ci if ((buf[1] & 0x7f) == rt->rtsp_streams[i]->sdp_payload_type) { 2151cabdff1aSopenharmony_ci *rtsp_st = rt->rtsp_streams[i]; 2152cabdff1aSopenharmony_ci return len; 2153cabdff1aSopenharmony_ci } 2154cabdff1aSopenharmony_ci } 2155cabdff1aSopenharmony_ci } 2156cabdff1aSopenharmony_ci } 2157cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Unable to pick stream for packet\n"); 2158cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 2159cabdff1aSopenharmony_ci} 2160cabdff1aSopenharmony_ci 2161cabdff1aSopenharmony_cistatic int read_packet(AVFormatContext *s, 2162cabdff1aSopenharmony_ci RTSPStream **rtsp_st, RTSPStream *first_queue_st, 2163cabdff1aSopenharmony_ci int64_t wait_end) 2164cabdff1aSopenharmony_ci{ 2165cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2166cabdff1aSopenharmony_ci int len; 2167cabdff1aSopenharmony_ci 2168cabdff1aSopenharmony_ci switch(rt->lower_transport) { 2169cabdff1aSopenharmony_ci default: 2170cabdff1aSopenharmony_ci#if CONFIG_RTSP_DEMUXER 2171cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_TCP: 2172cabdff1aSopenharmony_ci len = ff_rtsp_tcp_read_packet(s, rtsp_st, rt->recvbuf, RECVBUF_SIZE); 2173cabdff1aSopenharmony_ci break; 2174cabdff1aSopenharmony_ci#endif 2175cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_UDP: 2176cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: 2177cabdff1aSopenharmony_ci len = udp_read_packet(s, rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end); 2178cabdff1aSopenharmony_ci if (len > 0 && (*rtsp_st)->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) 2179cabdff1aSopenharmony_ci ff_rtp_check_and_send_back_rr((*rtsp_st)->transport_priv, (*rtsp_st)->rtp_handle, NULL, len); 2180cabdff1aSopenharmony_ci break; 2181cabdff1aSopenharmony_ci case RTSP_LOWER_TRANSPORT_CUSTOM: 2182cabdff1aSopenharmony_ci if (first_queue_st && rt->transport == RTSP_TRANSPORT_RTP && 2183cabdff1aSopenharmony_ci wait_end && wait_end < av_gettime_relative()) 2184cabdff1aSopenharmony_ci len = AVERROR(EAGAIN); 2185cabdff1aSopenharmony_ci else 2186cabdff1aSopenharmony_ci len = avio_read_partial(s->pb, rt->recvbuf, RECVBUF_SIZE); 2187cabdff1aSopenharmony_ci len = pick_stream(s, rtsp_st, rt->recvbuf, len); 2188cabdff1aSopenharmony_ci if (len > 0 && (*rtsp_st)->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) 2189cabdff1aSopenharmony_ci ff_rtp_check_and_send_back_rr((*rtsp_st)->transport_priv, NULL, s->pb, len); 2190cabdff1aSopenharmony_ci break; 2191cabdff1aSopenharmony_ci } 2192cabdff1aSopenharmony_ci 2193cabdff1aSopenharmony_ci if (len == 0) 2194cabdff1aSopenharmony_ci return AVERROR_EOF; 2195cabdff1aSopenharmony_ci 2196cabdff1aSopenharmony_ci return len; 2197cabdff1aSopenharmony_ci} 2198cabdff1aSopenharmony_ci 2199cabdff1aSopenharmony_ciint ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) 2200cabdff1aSopenharmony_ci{ 2201cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2202cabdff1aSopenharmony_ci int ret, len; 2203cabdff1aSopenharmony_ci RTSPStream *rtsp_st, *first_queue_st = NULL; 2204cabdff1aSopenharmony_ci int64_t wait_end = 0; 2205cabdff1aSopenharmony_ci 2206cabdff1aSopenharmony_ci if (rt->nb_byes == rt->nb_rtsp_streams) 2207cabdff1aSopenharmony_ci return AVERROR_EOF; 2208cabdff1aSopenharmony_ci 2209cabdff1aSopenharmony_ci /* get next frames from the same RTP packet */ 2210cabdff1aSopenharmony_ci if (rt->cur_transport_priv) { 2211cabdff1aSopenharmony_ci if (rt->transport == RTSP_TRANSPORT_RDT) { 2212cabdff1aSopenharmony_ci ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); 2213cabdff1aSopenharmony_ci } else if (rt->transport == RTSP_TRANSPORT_RTP) { 2214cabdff1aSopenharmony_ci ret = ff_rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); 2215cabdff1aSopenharmony_ci } else if (CONFIG_RTPDEC && rt->ts) { 2216cabdff1aSopenharmony_ci ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos); 2217cabdff1aSopenharmony_ci if (ret >= 0) { 2218cabdff1aSopenharmony_ci rt->recvbuf_pos += ret; 2219cabdff1aSopenharmony_ci ret = rt->recvbuf_pos < rt->recvbuf_len; 2220cabdff1aSopenharmony_ci } 2221cabdff1aSopenharmony_ci } else 2222cabdff1aSopenharmony_ci ret = -1; 2223cabdff1aSopenharmony_ci if (ret == 0) { 2224cabdff1aSopenharmony_ci rt->cur_transport_priv = NULL; 2225cabdff1aSopenharmony_ci return 0; 2226cabdff1aSopenharmony_ci } else if (ret == 1) { 2227cabdff1aSopenharmony_ci return 0; 2228cabdff1aSopenharmony_ci } else 2229cabdff1aSopenharmony_ci rt->cur_transport_priv = NULL; 2230cabdff1aSopenharmony_ci } 2231cabdff1aSopenharmony_ci 2232cabdff1aSopenharmony_ciredo: 2233cabdff1aSopenharmony_ci if (rt->transport == RTSP_TRANSPORT_RTP) { 2234cabdff1aSopenharmony_ci int i; 2235cabdff1aSopenharmony_ci int64_t first_queue_time = 0; 2236cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2237cabdff1aSopenharmony_ci RTPDemuxContext *rtpctx = rt->rtsp_streams[i]->transport_priv; 2238cabdff1aSopenharmony_ci int64_t queue_time; 2239cabdff1aSopenharmony_ci if (!rtpctx) 2240cabdff1aSopenharmony_ci continue; 2241cabdff1aSopenharmony_ci queue_time = ff_rtp_queued_packet_time(rtpctx); 2242cabdff1aSopenharmony_ci if (queue_time && (queue_time - first_queue_time < 0 || 2243cabdff1aSopenharmony_ci !first_queue_time)) { 2244cabdff1aSopenharmony_ci first_queue_time = queue_time; 2245cabdff1aSopenharmony_ci first_queue_st = rt->rtsp_streams[i]; 2246cabdff1aSopenharmony_ci } 2247cabdff1aSopenharmony_ci } 2248cabdff1aSopenharmony_ci if (first_queue_time) { 2249cabdff1aSopenharmony_ci wait_end = first_queue_time + s->max_delay; 2250cabdff1aSopenharmony_ci } else { 2251cabdff1aSopenharmony_ci wait_end = 0; 2252cabdff1aSopenharmony_ci first_queue_st = NULL; 2253cabdff1aSopenharmony_ci } 2254cabdff1aSopenharmony_ci } 2255cabdff1aSopenharmony_ci 2256cabdff1aSopenharmony_ci /* read next RTP packet */ 2257cabdff1aSopenharmony_ci if (!rt->recvbuf) { 2258cabdff1aSopenharmony_ci rt->recvbuf = av_malloc(RECVBUF_SIZE); 2259cabdff1aSopenharmony_ci if (!rt->recvbuf) 2260cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2261cabdff1aSopenharmony_ci } 2262cabdff1aSopenharmony_ci 2263cabdff1aSopenharmony_ci len = read_packet(s, &rtsp_st, first_queue_st, wait_end); 2264cabdff1aSopenharmony_ci if (len == AVERROR(EAGAIN) && first_queue_st && 2265cabdff1aSopenharmony_ci rt->transport == RTSP_TRANSPORT_RTP) { 2266cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, 2267cabdff1aSopenharmony_ci "max delay reached. need to consume packet\n"); 2268cabdff1aSopenharmony_ci rtsp_st = first_queue_st; 2269cabdff1aSopenharmony_ci ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, NULL, 0); 2270cabdff1aSopenharmony_ci goto end; 2271cabdff1aSopenharmony_ci } 2272cabdff1aSopenharmony_ci if (len < 0) 2273cabdff1aSopenharmony_ci return len; 2274cabdff1aSopenharmony_ci 2275cabdff1aSopenharmony_ci if (rt->transport == RTSP_TRANSPORT_RDT) { 2276cabdff1aSopenharmony_ci ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); 2277cabdff1aSopenharmony_ci } else if (rt->transport == RTSP_TRANSPORT_RTP) { 2278cabdff1aSopenharmony_ci ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); 2279cabdff1aSopenharmony_ci if (rtsp_st->feedback) { 2280cabdff1aSopenharmony_ci AVIOContext *pb = NULL; 2281cabdff1aSopenharmony_ci if (rt->lower_transport == RTSP_LOWER_TRANSPORT_CUSTOM) 2282cabdff1aSopenharmony_ci pb = s->pb; 2283cabdff1aSopenharmony_ci ff_rtp_send_rtcp_feedback(rtsp_st->transport_priv, rtsp_st->rtp_handle, pb); 2284cabdff1aSopenharmony_ci } 2285cabdff1aSopenharmony_ci if (ret < 0) { 2286cabdff1aSopenharmony_ci /* Either bad packet, or a RTCP packet. Check if the 2287cabdff1aSopenharmony_ci * first_rtcp_ntp_time field was initialized. */ 2288cabdff1aSopenharmony_ci RTPDemuxContext *rtpctx = rtsp_st->transport_priv; 2289cabdff1aSopenharmony_ci if (rtpctx->first_rtcp_ntp_time != AV_NOPTS_VALUE) { 2290cabdff1aSopenharmony_ci /* first_rtcp_ntp_time has been initialized for this stream, 2291cabdff1aSopenharmony_ci * copy the same value to all other uninitialized streams, 2292cabdff1aSopenharmony_ci * in order to map their timestamp origin to the same ntp time 2293cabdff1aSopenharmony_ci * as this one. */ 2294cabdff1aSopenharmony_ci int i; 2295cabdff1aSopenharmony_ci AVStream *st = NULL; 2296cabdff1aSopenharmony_ci if (rtsp_st->stream_index >= 0) 2297cabdff1aSopenharmony_ci st = s->streams[rtsp_st->stream_index]; 2298cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2299cabdff1aSopenharmony_ci RTPDemuxContext *rtpctx2 = rt->rtsp_streams[i]->transport_priv; 2300cabdff1aSopenharmony_ci AVStream *st2 = NULL; 2301cabdff1aSopenharmony_ci if (rt->rtsp_streams[i]->stream_index >= 0) 2302cabdff1aSopenharmony_ci st2 = s->streams[rt->rtsp_streams[i]->stream_index]; 2303cabdff1aSopenharmony_ci if (rtpctx2 && st && st2 && 2304cabdff1aSopenharmony_ci rtpctx2->first_rtcp_ntp_time == AV_NOPTS_VALUE) { 2305cabdff1aSopenharmony_ci rtpctx2->first_rtcp_ntp_time = rtpctx->first_rtcp_ntp_time; 2306cabdff1aSopenharmony_ci rtpctx2->rtcp_ts_offset = av_rescale_q( 2307cabdff1aSopenharmony_ci rtpctx->rtcp_ts_offset, st->time_base, 2308cabdff1aSopenharmony_ci st2->time_base); 2309cabdff1aSopenharmony_ci } 2310cabdff1aSopenharmony_ci } 2311cabdff1aSopenharmony_ci // Make real NTP start time available in AVFormatContext 2312cabdff1aSopenharmony_ci if (s->start_time_realtime == AV_NOPTS_VALUE) { 2313cabdff1aSopenharmony_ci s->start_time_realtime = av_rescale (rtpctx->first_rtcp_ntp_time - (NTP_OFFSET << 32), 1000000, 1LL << 32); 2314cabdff1aSopenharmony_ci if (rtpctx->st) { 2315cabdff1aSopenharmony_ci s->start_time_realtime -= 2316cabdff1aSopenharmony_ci av_rescale_q (rtpctx->rtcp_ts_offset, rtpctx->st->time_base, AV_TIME_BASE_Q); 2317cabdff1aSopenharmony_ci } 2318cabdff1aSopenharmony_ci } 2319cabdff1aSopenharmony_ci } 2320cabdff1aSopenharmony_ci if (ret == -RTCP_BYE) { 2321cabdff1aSopenharmony_ci rt->nb_byes++; 2322cabdff1aSopenharmony_ci 2323cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Received BYE for stream %d (%d/%d)\n", 2324cabdff1aSopenharmony_ci rtsp_st->stream_index, rt->nb_byes, rt->nb_rtsp_streams); 2325cabdff1aSopenharmony_ci 2326cabdff1aSopenharmony_ci if (rt->nb_byes == rt->nb_rtsp_streams) 2327cabdff1aSopenharmony_ci return AVERROR_EOF; 2328cabdff1aSopenharmony_ci } 2329cabdff1aSopenharmony_ci } 2330cabdff1aSopenharmony_ci } else if (CONFIG_RTPDEC && rt->ts) { 2331cabdff1aSopenharmony_ci ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf, len); 2332cabdff1aSopenharmony_ci if (ret >= 0) { 2333cabdff1aSopenharmony_ci if (ret < len) { 2334cabdff1aSopenharmony_ci rt->recvbuf_len = len; 2335cabdff1aSopenharmony_ci rt->recvbuf_pos = ret; 2336cabdff1aSopenharmony_ci rt->cur_transport_priv = rt->ts; 2337cabdff1aSopenharmony_ci return 1; 2338cabdff1aSopenharmony_ci } else { 2339cabdff1aSopenharmony_ci ret = 0; 2340cabdff1aSopenharmony_ci } 2341cabdff1aSopenharmony_ci } 2342cabdff1aSopenharmony_ci } else { 2343cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 2344cabdff1aSopenharmony_ci } 2345cabdff1aSopenharmony_ciend: 2346cabdff1aSopenharmony_ci if (ret < 0) 2347cabdff1aSopenharmony_ci goto redo; 2348cabdff1aSopenharmony_ci if (ret == 1) 2349cabdff1aSopenharmony_ci /* more packets may follow, so we save the RTP context */ 2350cabdff1aSopenharmony_ci rt->cur_transport_priv = rtsp_st->transport_priv; 2351cabdff1aSopenharmony_ci 2352cabdff1aSopenharmony_ci return ret; 2353cabdff1aSopenharmony_ci} 2354cabdff1aSopenharmony_ci#endif /* CONFIG_RTPDEC */ 2355cabdff1aSopenharmony_ci 2356cabdff1aSopenharmony_ci#if CONFIG_SDP_DEMUXER 2357cabdff1aSopenharmony_cistatic int sdp_probe(const AVProbeData *p1) 2358cabdff1aSopenharmony_ci{ 2359cabdff1aSopenharmony_ci const char *p = p1->buf, *p_end = p1->buf + p1->buf_size; 2360cabdff1aSopenharmony_ci 2361cabdff1aSopenharmony_ci /* we look for a line beginning "c=IN IP" */ 2362cabdff1aSopenharmony_ci while (p < p_end && *p != '\0') { 2363cabdff1aSopenharmony_ci if (sizeof("c=IN IP") - 1 < p_end - p && 2364cabdff1aSopenharmony_ci av_strstart(p, "c=IN IP", NULL)) 2365cabdff1aSopenharmony_ci return AVPROBE_SCORE_EXTENSION; 2366cabdff1aSopenharmony_ci 2367cabdff1aSopenharmony_ci while (p < p_end - 1 && *p != '\n') p++; 2368cabdff1aSopenharmony_ci if (++p >= p_end) 2369cabdff1aSopenharmony_ci break; 2370cabdff1aSopenharmony_ci if (*p == '\r') 2371cabdff1aSopenharmony_ci p++; 2372cabdff1aSopenharmony_ci } 2373cabdff1aSopenharmony_ci return 0; 2374cabdff1aSopenharmony_ci} 2375cabdff1aSopenharmony_ci 2376cabdff1aSopenharmony_cistatic void append_source_addrs(char *buf, int size, const char *name, 2377cabdff1aSopenharmony_ci int count, struct RTSPSource **addrs) 2378cabdff1aSopenharmony_ci{ 2379cabdff1aSopenharmony_ci int i; 2380cabdff1aSopenharmony_ci if (!count) 2381cabdff1aSopenharmony_ci return; 2382cabdff1aSopenharmony_ci av_strlcatf(buf, size, "&%s=%s", name, addrs[0]->addr); 2383cabdff1aSopenharmony_ci for (i = 1; i < count; i++) 2384cabdff1aSopenharmony_ci av_strlcatf(buf, size, ",%s", addrs[i]->addr); 2385cabdff1aSopenharmony_ci} 2386cabdff1aSopenharmony_ci 2387cabdff1aSopenharmony_cistatic int sdp_read_header(AVFormatContext *s) 2388cabdff1aSopenharmony_ci{ 2389cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2390cabdff1aSopenharmony_ci RTSPStream *rtsp_st; 2391cabdff1aSopenharmony_ci int i, err; 2392cabdff1aSopenharmony_ci char url[MAX_URL_SIZE]; 2393cabdff1aSopenharmony_ci AVBPrint bp; 2394cabdff1aSopenharmony_ci 2395cabdff1aSopenharmony_ci if (!ff_network_init()) 2396cabdff1aSopenharmony_ci return AVERROR(EIO); 2397cabdff1aSopenharmony_ci 2398cabdff1aSopenharmony_ci if (s->max_delay < 0) /* Not set by the caller */ 2399cabdff1aSopenharmony_ci s->max_delay = DEFAULT_REORDERING_DELAY; 2400cabdff1aSopenharmony_ci if (rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO) 2401cabdff1aSopenharmony_ci rt->lower_transport = RTSP_LOWER_TRANSPORT_CUSTOM; 2402cabdff1aSopenharmony_ci 2403cabdff1aSopenharmony_ci /* read the whole sdp file */ 2404cabdff1aSopenharmony_ci av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); 2405cabdff1aSopenharmony_ci err = avio_read_to_bprint(s->pb, &bp, INT_MAX); 2406cabdff1aSopenharmony_ci if (err < 0 ) { 2407cabdff1aSopenharmony_ci ff_network_close(); 2408cabdff1aSopenharmony_ci av_bprint_finalize(&bp, NULL); 2409cabdff1aSopenharmony_ci return err; 2410cabdff1aSopenharmony_ci } 2411cabdff1aSopenharmony_ci err = ff_sdp_parse(s, bp.str); 2412cabdff1aSopenharmony_ci av_bprint_finalize(&bp, NULL); 2413cabdff1aSopenharmony_ci if (err) goto fail; 2414cabdff1aSopenharmony_ci 2415cabdff1aSopenharmony_ci /* open each RTP stream */ 2416cabdff1aSopenharmony_ci for (i = 0; i < rt->nb_rtsp_streams; i++) { 2417cabdff1aSopenharmony_ci char namebuf[50]; 2418cabdff1aSopenharmony_ci rtsp_st = rt->rtsp_streams[i]; 2419cabdff1aSopenharmony_ci 2420cabdff1aSopenharmony_ci if (!(rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO)) { 2421cabdff1aSopenharmony_ci AVDictionary *opts = map_to_opts(rt); 2422cabdff1aSopenharmony_ci char buf[MAX_URL_SIZE]; 2423cabdff1aSopenharmony_ci const char *p; 2424cabdff1aSopenharmony_ci 2425cabdff1aSopenharmony_ci err = getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, 2426cabdff1aSopenharmony_ci sizeof(rtsp_st->sdp_ip), 2427cabdff1aSopenharmony_ci namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); 2428cabdff1aSopenharmony_ci if (err) { 2429cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "getnameinfo: %s\n", gai_strerror(err)); 2430cabdff1aSopenharmony_ci err = AVERROR(EIO); 2431cabdff1aSopenharmony_ci av_dict_free(&opts); 2432cabdff1aSopenharmony_ci goto fail; 2433cabdff1aSopenharmony_ci } 2434cabdff1aSopenharmony_ci ff_url_join(url, sizeof(url), "rtp", NULL, 2435cabdff1aSopenharmony_ci namebuf, rtsp_st->sdp_port, 2436cabdff1aSopenharmony_ci "?localport=%d&ttl=%d&connect=%d&write_to_source=%d", 2437cabdff1aSopenharmony_ci rtsp_st->sdp_port, rtsp_st->sdp_ttl, 2438cabdff1aSopenharmony_ci rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0, 2439cabdff1aSopenharmony_ci rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0); 2440cabdff1aSopenharmony_ci 2441cabdff1aSopenharmony_ci p = strchr(s->url, '?'); 2442cabdff1aSopenharmony_ci if (p && av_find_info_tag(buf, sizeof(buf), "localaddr", p)) 2443cabdff1aSopenharmony_ci av_strlcatf(url, sizeof(url), "&localaddr=%s", buf); 2444cabdff1aSopenharmony_ci else if (rt->localaddr && rt->localaddr[0]) 2445cabdff1aSopenharmony_ci av_strlcatf(url, sizeof(url), "&localaddr=%s", rt->localaddr); 2446cabdff1aSopenharmony_ci append_source_addrs(url, sizeof(url), "sources", 2447cabdff1aSopenharmony_ci rtsp_st->nb_include_source_addrs, 2448cabdff1aSopenharmony_ci rtsp_st->include_source_addrs); 2449cabdff1aSopenharmony_ci append_source_addrs(url, sizeof(url), "block", 2450cabdff1aSopenharmony_ci rtsp_st->nb_exclude_source_addrs, 2451cabdff1aSopenharmony_ci rtsp_st->exclude_source_addrs); 2452cabdff1aSopenharmony_ci err = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ, 2453cabdff1aSopenharmony_ci &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); 2454cabdff1aSopenharmony_ci 2455cabdff1aSopenharmony_ci av_dict_free(&opts); 2456cabdff1aSopenharmony_ci 2457cabdff1aSopenharmony_ci if (err < 0) { 2458cabdff1aSopenharmony_ci err = AVERROR_INVALIDDATA; 2459cabdff1aSopenharmony_ci goto fail; 2460cabdff1aSopenharmony_ci } 2461cabdff1aSopenharmony_ci } 2462cabdff1aSopenharmony_ci if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st))) 2463cabdff1aSopenharmony_ci goto fail; 2464cabdff1aSopenharmony_ci } 2465cabdff1aSopenharmony_ci return 0; 2466cabdff1aSopenharmony_cifail: 2467cabdff1aSopenharmony_ci ff_rtsp_close_streams(s); 2468cabdff1aSopenharmony_ci ff_network_close(); 2469cabdff1aSopenharmony_ci return err; 2470cabdff1aSopenharmony_ci} 2471cabdff1aSopenharmony_ci 2472cabdff1aSopenharmony_cistatic int sdp_read_close(AVFormatContext *s) 2473cabdff1aSopenharmony_ci{ 2474cabdff1aSopenharmony_ci ff_rtsp_close_streams(s); 2475cabdff1aSopenharmony_ci ff_network_close(); 2476cabdff1aSopenharmony_ci return 0; 2477cabdff1aSopenharmony_ci} 2478cabdff1aSopenharmony_ci 2479cabdff1aSopenharmony_cistatic const AVClass sdp_demuxer_class = { 2480cabdff1aSopenharmony_ci .class_name = "SDP demuxer", 2481cabdff1aSopenharmony_ci .item_name = av_default_item_name, 2482cabdff1aSopenharmony_ci .option = sdp_options, 2483cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 2484cabdff1aSopenharmony_ci}; 2485cabdff1aSopenharmony_ci 2486cabdff1aSopenharmony_ciconst AVInputFormat ff_sdp_demuxer = { 2487cabdff1aSopenharmony_ci .name = "sdp", 2488cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("SDP"), 2489cabdff1aSopenharmony_ci .priv_data_size = sizeof(RTSPState), 2490cabdff1aSopenharmony_ci .read_probe = sdp_probe, 2491cabdff1aSopenharmony_ci .read_header = sdp_read_header, 2492cabdff1aSopenharmony_ci .read_packet = ff_rtsp_fetch_packet, 2493cabdff1aSopenharmony_ci .read_close = sdp_read_close, 2494cabdff1aSopenharmony_ci .priv_class = &sdp_demuxer_class, 2495cabdff1aSopenharmony_ci}; 2496cabdff1aSopenharmony_ci#endif /* CONFIG_SDP_DEMUXER */ 2497cabdff1aSopenharmony_ci 2498cabdff1aSopenharmony_ci#if CONFIG_RTP_DEMUXER 2499cabdff1aSopenharmony_cistatic int rtp_probe(const AVProbeData *p) 2500cabdff1aSopenharmony_ci{ 2501cabdff1aSopenharmony_ci if (av_strstart(p->filename, "rtp:", NULL)) 2502cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 2503cabdff1aSopenharmony_ci return 0; 2504cabdff1aSopenharmony_ci} 2505cabdff1aSopenharmony_ci 2506cabdff1aSopenharmony_cistatic int rtp_read_header(AVFormatContext *s) 2507cabdff1aSopenharmony_ci{ 2508cabdff1aSopenharmony_ci uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; 2509cabdff1aSopenharmony_ci char host[500], filters_buf[1000]; 2510cabdff1aSopenharmony_ci int ret, port; 2511cabdff1aSopenharmony_ci URLContext* in = NULL; 2512cabdff1aSopenharmony_ci int payload_type; 2513cabdff1aSopenharmony_ci AVCodecParameters *par = NULL; 2514cabdff1aSopenharmony_ci struct sockaddr_storage addr; 2515cabdff1aSopenharmony_ci FFIOContext pb; 2516cabdff1aSopenharmony_ci socklen_t addrlen = sizeof(addr); 2517cabdff1aSopenharmony_ci RTSPState *rt = s->priv_data; 2518cabdff1aSopenharmony_ci const char *p; 2519cabdff1aSopenharmony_ci AVBPrint sdp; 2520cabdff1aSopenharmony_ci AVDictionary *opts = NULL; 2521cabdff1aSopenharmony_ci 2522cabdff1aSopenharmony_ci if (!ff_network_init()) 2523cabdff1aSopenharmony_ci return AVERROR(EIO); 2524cabdff1aSopenharmony_ci 2525cabdff1aSopenharmony_ci opts = map_to_opts(rt); 2526cabdff1aSopenharmony_ci ret = ffurl_open_whitelist(&in, s->url, AVIO_FLAG_READ, 2527cabdff1aSopenharmony_ci &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); 2528cabdff1aSopenharmony_ci av_dict_free(&opts); 2529cabdff1aSopenharmony_ci if (ret) 2530cabdff1aSopenharmony_ci goto fail; 2531cabdff1aSopenharmony_ci 2532cabdff1aSopenharmony_ci while (1) { 2533cabdff1aSopenharmony_ci ret = ffurl_read(in, recvbuf, sizeof(recvbuf)); 2534cabdff1aSopenharmony_ci if (ret == AVERROR(EAGAIN)) 2535cabdff1aSopenharmony_ci continue; 2536cabdff1aSopenharmony_ci if (ret < 0) 2537cabdff1aSopenharmony_ci goto fail; 2538cabdff1aSopenharmony_ci if (ret < 12) { 2539cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Received too short packet\n"); 2540cabdff1aSopenharmony_ci continue; 2541cabdff1aSopenharmony_ci } 2542cabdff1aSopenharmony_ci 2543cabdff1aSopenharmony_ci if ((recvbuf[0] & 0xc0) != 0x80) { 2544cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Unsupported RTP version packet " 2545cabdff1aSopenharmony_ci "received\n"); 2546cabdff1aSopenharmony_ci continue; 2547cabdff1aSopenharmony_ci } 2548cabdff1aSopenharmony_ci 2549cabdff1aSopenharmony_ci if (RTP_PT_IS_RTCP(recvbuf[1])) 2550cabdff1aSopenharmony_ci continue; 2551cabdff1aSopenharmony_ci 2552cabdff1aSopenharmony_ci payload_type = recvbuf[1] & 0x7f; 2553cabdff1aSopenharmony_ci break; 2554cabdff1aSopenharmony_ci } 2555cabdff1aSopenharmony_ci getsockname(ffurl_get_file_handle(in), (struct sockaddr*) &addr, &addrlen); 2556cabdff1aSopenharmony_ci ffurl_closep(&in); 2557cabdff1aSopenharmony_ci 2558cabdff1aSopenharmony_ci par = avcodec_parameters_alloc(); 2559cabdff1aSopenharmony_ci if (!par) { 2560cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 2561cabdff1aSopenharmony_ci goto fail; 2562cabdff1aSopenharmony_ci } 2563cabdff1aSopenharmony_ci 2564cabdff1aSopenharmony_ci if (ff_rtp_get_codec_info(par, payload_type)) { 2565cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to receive RTP payload type %d " 2566cabdff1aSopenharmony_ci "without an SDP file describing it\n", 2567cabdff1aSopenharmony_ci payload_type); 2568cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 2569cabdff1aSopenharmony_ci goto fail; 2570cabdff1aSopenharmony_ci } 2571cabdff1aSopenharmony_ci if (par->codec_type != AVMEDIA_TYPE_DATA) { 2572cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Guessing on RTP content - if not received " 2573cabdff1aSopenharmony_ci "properly you need an SDP file " 2574cabdff1aSopenharmony_ci "describing it\n"); 2575cabdff1aSopenharmony_ci } 2576cabdff1aSopenharmony_ci 2577cabdff1aSopenharmony_ci av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, 2578cabdff1aSopenharmony_ci NULL, 0, s->url); 2579cabdff1aSopenharmony_ci 2580cabdff1aSopenharmony_ci av_bprint_init(&sdp, 0, AV_BPRINT_SIZE_UNLIMITED); 2581cabdff1aSopenharmony_ci av_bprintf(&sdp, "v=0\r\nc=IN IP%d %s\r\n", 2582cabdff1aSopenharmony_ci addr.ss_family == AF_INET ? 4 : 6, host); 2583cabdff1aSopenharmony_ci 2584cabdff1aSopenharmony_ci p = strchr(s->url, '?'); 2585cabdff1aSopenharmony_ci if (p) { 2586cabdff1aSopenharmony_ci static const char filters[][2][8] = { { "sources", "incl" }, 2587cabdff1aSopenharmony_ci { "block", "excl" } }; 2588cabdff1aSopenharmony_ci int i; 2589cabdff1aSopenharmony_ci char *q; 2590cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(filters); i++) { 2591cabdff1aSopenharmony_ci if (av_find_info_tag(filters_buf, sizeof(filters_buf), filters[i][0], p)) { 2592cabdff1aSopenharmony_ci q = filters_buf; 2593cabdff1aSopenharmony_ci while ((q = strchr(q, ',')) != NULL) 2594cabdff1aSopenharmony_ci *q = ' '; 2595cabdff1aSopenharmony_ci av_bprintf(&sdp, "a=source-filter:%s IN IP%d %s %s\r\n", 2596cabdff1aSopenharmony_ci filters[i][1], 2597cabdff1aSopenharmony_ci addr.ss_family == AF_INET ? 4 : 6, host, 2598cabdff1aSopenharmony_ci filters_buf); 2599cabdff1aSopenharmony_ci } 2600cabdff1aSopenharmony_ci } 2601cabdff1aSopenharmony_ci } 2602cabdff1aSopenharmony_ci 2603cabdff1aSopenharmony_ci av_bprintf(&sdp, "m=%s %d RTP/AVP %d\r\n", 2604cabdff1aSopenharmony_ci par->codec_type == AVMEDIA_TYPE_DATA ? "application" : 2605cabdff1aSopenharmony_ci par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio", 2606cabdff1aSopenharmony_ci port, payload_type); 2607cabdff1aSopenharmony_ci av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp.str); 2608cabdff1aSopenharmony_ci if (!av_bprint_is_complete(&sdp)) 2609cabdff1aSopenharmony_ci goto fail_nobuf; 2610cabdff1aSopenharmony_ci avcodec_parameters_free(&par); 2611cabdff1aSopenharmony_ci 2612cabdff1aSopenharmony_ci ffio_init_context(&pb, sdp.str, sdp.len, 0, NULL, NULL, NULL, NULL); 2613cabdff1aSopenharmony_ci s->pb = &pb.pub; 2614cabdff1aSopenharmony_ci 2615cabdff1aSopenharmony_ci /* if sdp_read_header() fails then following ff_network_close() cancels out */ 2616cabdff1aSopenharmony_ci /* ff_network_init() at the start of this function. Otherwise it cancels out */ 2617cabdff1aSopenharmony_ci /* ff_network_init() inside sdp_read_header() */ 2618cabdff1aSopenharmony_ci ff_network_close(); 2619cabdff1aSopenharmony_ci 2620cabdff1aSopenharmony_ci rt->media_type_mask = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1; 2621cabdff1aSopenharmony_ci 2622cabdff1aSopenharmony_ci ret = sdp_read_header(s); 2623cabdff1aSopenharmony_ci s->pb = NULL; 2624cabdff1aSopenharmony_ci av_bprint_finalize(&sdp, NULL); 2625cabdff1aSopenharmony_ci return ret; 2626cabdff1aSopenharmony_ci 2627cabdff1aSopenharmony_cifail_nobuf: 2628cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 2629cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "rtp_read_header(): not enough buffer space for sdp-headers\n"); 2630cabdff1aSopenharmony_ci av_bprint_finalize(&sdp, NULL); 2631cabdff1aSopenharmony_cifail: 2632cabdff1aSopenharmony_ci avcodec_parameters_free(&par); 2633cabdff1aSopenharmony_ci ffurl_closep(&in); 2634cabdff1aSopenharmony_ci ff_network_close(); 2635cabdff1aSopenharmony_ci return ret; 2636cabdff1aSopenharmony_ci} 2637cabdff1aSopenharmony_ci 2638cabdff1aSopenharmony_cistatic const AVClass rtp_demuxer_class = { 2639cabdff1aSopenharmony_ci .class_name = "RTP demuxer", 2640cabdff1aSopenharmony_ci .item_name = av_default_item_name, 2641cabdff1aSopenharmony_ci .option = rtp_options, 2642cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 2643cabdff1aSopenharmony_ci}; 2644cabdff1aSopenharmony_ci 2645cabdff1aSopenharmony_ciconst AVInputFormat ff_rtp_demuxer = { 2646cabdff1aSopenharmony_ci .name = "rtp", 2647cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("RTP input"), 2648cabdff1aSopenharmony_ci .priv_data_size = sizeof(RTSPState), 2649cabdff1aSopenharmony_ci .read_probe = rtp_probe, 2650cabdff1aSopenharmony_ci .read_header = rtp_read_header, 2651cabdff1aSopenharmony_ci .read_packet = ff_rtsp_fetch_packet, 2652cabdff1aSopenharmony_ci .read_close = sdp_read_close, 2653cabdff1aSopenharmony_ci .flags = AVFMT_NOFILE, 2654cabdff1aSopenharmony_ci .priv_class = &rtp_demuxer_class, 2655cabdff1aSopenharmony_ci}; 2656cabdff1aSopenharmony_ci#endif /* CONFIG_RTP_DEMUXER */ 2657