aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAman Karmani <aman@tmm1.net>2020-12-16 12:40:16 -0800
committerAman Karmani <aman@tmm1.net>2020-12-28 14:08:44 -0800
commit98b76bb11f3d2bfb0f12373e9930c11ee48e8940 (patch)
treed4ecfb8d4fc4da3304968d2aadf30d59341ee5fb
parent292e41ce650a7b5ca5de4ae87fff0d6a90d9fc97 (diff)
downloadffmpeg-98b76bb11f3d2bfb0f12373e9930c11ee48e8940.tar.gz
avformat/rtsp: add support for satip://
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, but 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][4]. This commit adds proper spec-compliant support for SAT>IP, including: - support for the satip:// psuedo-protocol[5] - 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 This patch has been validated against multiple SAT>IP vendor devices: - Telestar Digibit R2 (https://telestar.de/en/produkt/digibit-r1-2/) - Kathrein EXIP 418 (https://www.kathrein-ds.com/en/produkte/sat-zf-verteiltechnik/sat-ip/227/exip-418) - Kathrein EXIP 4124 (https://www.kathrein-ds.com/en/products/sat-if-signal-distribution/sat-ip/226/exip-4124) - Megasat MEG-8000 (https://www.megasat.tv/produkt/sat-ip-server-3/) - Megasat Twin (https://www.megasat.tv/en/produkt/sat-ip-server-twin/) - Triax TSS 400 (https://www.conrad.com/p/triax-tss-400-mkii-sat-ip-server-595256) [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 [4] https://forum.kodi.tv/showthread.php?tid=359072&pid=2995884#pid2995884 [5] https://www.satip.info/resources/channel-lists/
-rw-r--r--libavformat/rtsp.c53
-rw-r--r--libavformat/rtsp.h6
-rw-r--r--libavformat/rtspdec.c1
3 files changed, 54 insertions, 6 deletions
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index ac38fd05d0..1f506129eb 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -252,6 +252,25 @@ 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 = av_mallocz(sizeof(RTSPStream));
+ if (!rtsp_st)
+ return AVERROR(ENOMEM);
+ dynarray_add(&rt->rtsp_streams,
+ &rt->nb_rtsp_streams, rtsp_st);
+
+ rtsp_st->sdp_payload_type = 33; // MP2T
+ av_strlcpy(rtsp_st->control_url,
+ rt->control_uri, sizeof(rtsp_st->control_url));
+
+ rtsp_st->stream_index = -1;
+ init_rtp_handler(&ff_mpegts_dynamic_handler, rtsp_st, NULL);
+ finalize_rtp_handler_init(s, rtsp_st, NULL);
+ return 0;
+}
+
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */
static int sdp_parse_rtpmap(AVFormatContext *s,
AVStream *st, RTSPStream *rtsp_st,
@@ -1116,6 +1135,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 +1517,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_strlcpy(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 +1583,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 +1743,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 +1893,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 +1930,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..239ea8a0eb 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -188,6 +188,11 @@ typedef struct RTSPMessageHeader {
* Content type header
*/
char content_type[64];
+
+ /**
+ * SAT>IP com.ses.streamID 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;