From patchwork Tue Dec 22 00:35:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 24612 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id A95E444A0ED for ; Tue, 22 Dec 2020 03:00:14 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7E46868A898; Tue, 22 Dec 2020 03:00:14 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-il1-f193.google.com (mail-il1-f193.google.com [209.85.166.193]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 733C468A7D4 for ; Tue, 22 Dec 2020 03:00:08 +0200 (EET) Received: by mail-il1-f193.google.com with SMTP id k8so10561575ilr.4 for ; Mon, 21 Dec 2020 17:00:08 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=d6fmBjXYSn9JUhWJEvkcVKJ5EelUSosaJMYAulJo7BM=; b=QQ9aGYnSb4fuCaYv8EMKJlJljin3H9H+xqGx0w1o5qOFRukDahBUWcpCquBuOvukne BabIGtcSiS5lF5oxfJolLupbuodFvP/6mAwtcJ+1XfUtkQUaov8ueOHkJj67z93lLJWW dTQqe6T0lH5D/94LOV+CFy7bpwa+cSVllJweHV5d/ndNEwXXzzu3CGIz04d3CKQ0bB47 O0Cj6RT9f/Hi1Hl0SxL1jP4kYAM82qxTGHzd/zoVqQvQsF5A4yCZ7Ii9OFqs38KNKJJ6 d4FmaIUGwe87VyhcT37QZ6XtwSSutdBnnkH/F0XJE/dNISqpqnALWRbc1ITJUXHUtSat J1iQ== X-Gm-Message-State: AOAM532lnhfOPRdaGbvnLF/DFYpo+8n0l9JPQuP6hbEHHf0s0eGzw6Kz u1QtRq3Rg3fXyhAvP/EoV9KROWV51jsKpikc X-Google-Smtp-Source: ABdhPJyOuDlmZgThRJGlyzOQtozcq49d+lU/KBYcRsEG/mrIk9GmJr5L71rQ2FmiWYYLfceptJlMng== X-Received: by 2002:a63:d650:: with SMTP id d16mr17276827pgj.277.1608597383225; Mon, 21 Dec 2020 16:36:23 -0800 (PST) Received: from tmm1-imac.lan (ip72-194-222-34.sb.sd.cox.net. [72.194.222.34]) by smtp.gmail.com with ESMTPSA id z7sm18320780pfq.193.2020.12.21.16.36.21 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 Dec 2020 16:36:22 -0800 (PST) From: Aman Karmani To: ffmpeg-devel@ffmpeg.org Date: Mon, 21 Dec 2020 16:35:58 -0800 Message-Id: <20201222003600.27621-1-ffmpeg@tmm1.net> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/3] avformat/rtsp: add support for satip:// X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Aman Karmani Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Aman Karmani The SAT>IP protocol[1] is similar to RTSP. However SAT>IP servers are assumed to speak only MP2T, so DESCRIBE is not used in the same way. When no streams are active, DESCRIBE will return 404 according to the spec (see section 3.5.7). When streams are active, DESCRIBE will return a list of all current streams along with information about their signal strengths. Previously, attemping to use ffmpeg with a rtsp:// url that points to a SAT>IP server would work with some devices and fail due to 404 response on others. Further, if the SAT>IP server was already streaming, ffmpeg would incorrectly consume the DESCRIBE SDP response and join an existing tuner instead of requesting a new session with the URL provided by the user. These issues have been noted by many users across the internet[2][3]. This commit adds proper spec-compliant support for SAT>IP, including: - support for the satip:// psuedo-protocol - avoiding the use of DESCRIBE - parsing and consuming the com.ses.streamID response header - using "Transport: RTP/AVP;unicast" because the optional "/UDP" suffix confuses some servers [1] https://www.satip.info/sites/satip/files/resource/satip_specification_version_1_2_2.pdf [2] https://stackoverflow.com/questions/61194344/does-ffmpeg-violate-the-satip-specification-describe-syntax [3] https://github.com/kodi-pvr/pvr.iptvsimple/issues/196 --- libavformat/rtsp.c | 52 ++++++++++++++++++++++++++++++++++++++----- libavformat/rtsp.h | 6 +++++ libavformat/rtspdec.c | 1 + 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index c7ffa07d9e..4a863dbac3 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -252,6 +252,24 @@ static void finalize_rtp_handler_init(AVFormatContext *s, RTSPStream *rtsp_st, } } +static int init_satip_stream(AVFormatContext *s) +{ + RTSPState *rt = s->priv_data; + RTSPStream *rtsp_st; + rtsp_st = av_mallocz(sizeof(RTSPStream)); + if (!rtsp_st) + return AVERROR(ENOMEM); + rtsp_st->stream_index = -1; + dynarray_add(&rt->rtsp_streams, + &rt->nb_rtsp_streams, rtsp_st); + av_strlcpy(rtsp_st->control_url, + rt->control_uri, sizeof(rtsp_st->control_url)); + rtsp_st->sdp_payload_type = 33; // MP2T + init_rtp_handler(&ff_mpegts_dynamic_handler, rtsp_st, NULL); + finalize_rtp_handler_init(s, rtsp_st, NULL); + return 0; +} + /* parse the rtpmap description: /[/] */ static int sdp_parse_rtpmap(AVFormatContext *s, AVStream *st, RTSPStream *rtsp_st, @@ -1116,6 +1134,9 @@ void ff_rtsp_parse_line(AVFormatContext *s, } else if (av_stristart(p, "Content-Type:", &p)) { p += strspn(p, SPACE_CHARS); av_strlcpy(reply->content_type, p, sizeof(reply->content_type)); + } else if (av_stristart(p, "com.ses.streamID:", &p)) { + p += strspn(p, SPACE_CHARS); + av_strlcpy(reply->stream_id, p, sizeof(reply->stream_id)); } } @@ -1495,8 +1516,10 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, rtp_opened: port = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle); have_port: - snprintf(transport, sizeof(transport) - 1, - "%s/UDP;", trans_pref); + av_strlcat(transport, trans_pref, sizeof(transport)); + av_strlcat(transport, + rt->server_type == RTSP_SERVER_SATIP ? ";" : "/UDP;", + sizeof(transport)); if (rt->server_type != RTSP_SERVER_REAL) av_strlcat(transport, "unicast;", sizeof(transport)); av_strlcatf(transport, sizeof(transport), @@ -1559,6 +1582,15 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, goto fail; } + if (rt->server_type == RTSP_SERVER_SATIP && reply->stream_id[0]) { + char proto[128], host[128], path[512], auth[128]; + int port; + av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host), + &port, path, sizeof(path), rt->control_uri); + ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host, + port, "/stream=%s", reply->stream_id); + } + /* XXX: same protocol for all streams is required */ if (i > 0) { if (reply->transports[0].lower_transport != rt->lower_transport || @@ -1710,6 +1742,9 @@ redirect: lower_rtsp_proto = "tls"; default_port = RTSPS_DEFAULT_PORT; rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP; + } else if (!strcmp(proto, "satip")) { + av_strlcpy(proto, "rtsp", sizeof(proto)); + rt->server_type = RTSP_SERVER_SATIP; } if (*auth) { @@ -1857,7 +1892,9 @@ redirect: /* request options supported by the server; this also detects server * type */ - for (rt->server_type = RTSP_SERVER_RTP;;) { + if (rt->server_type != RTSP_SERVER_SATIP) + rt->server_type = RTSP_SERVER_RTP; + for (;;) { cmd[0] = 0; if (rt->server_type == RTSP_SERVER_REAL) av_strlcat(cmd, @@ -1892,9 +1929,12 @@ redirect: break; } - if (CONFIG_RTSP_DEMUXER && s->iformat) - err = ff_rtsp_setup_input_streams(s, reply); - else if (CONFIG_RTSP_MUXER) + if (CONFIG_RTSP_DEMUXER && s->iformat) { + if (rt->server_type == RTSP_SERVER_SATIP) + err = init_satip_stream(s); + else + err = ff_rtsp_setup_input_streams(s, reply); + } else if (CONFIG_RTSP_MUXER) err = ff_rtsp_setup_output_streams(s, host); else av_assert0(0); diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index b74cdc148a..c7c3b3cb52 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -188,6 +188,11 @@ typedef struct RTSPMessageHeader { * Content type header */ char content_type[64]; + + /** + * Stream ID header + */ + char stream_id[64]; } RTSPMessageHeader; /** @@ -210,6 +215,7 @@ enum RTSPServerType { RTSP_SERVER_RTP, /**< Standards-compliant RTP-server */ RTSP_SERVER_REAL, /**< Realmedia-style server */ RTSP_SERVER_WMS, /**< Windows Media server */ + RTSP_SERVER_SATIP,/**< SAT>IP server */ RTSP_SERVER_NB }; diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index bfbb01d586..113da975e1 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -724,6 +724,7 @@ static int rtsp_probe(const AVProbeData *p) #if CONFIG_TLS_PROTOCOL av_strstart(p->filename, "rtsps:", NULL) || #endif + av_strstart(p->filename, "satip:", NULL) || av_strstart(p->filename, "rtsp:", NULL)) return AVPROBE_SCORE_MAX; return 0;