From ea24781a9b508f92b6b2bb97ffca386898b70193 Mon Sep 17 00:00:00 2001 From: Nick Ruff Date: Fri, 11 Jun 2021 21:02:02 +0200 Subject: [PATCH] lavf/rtmp: Add option to set TCP_NODELAY for rtmp Suggested-By: ffmpeg@fb.com --- doc/protocols.texi | 5 +++++ libavformat/rtmppkt.c | 6 ++++++ libavformat/rtmpproto.c | 8 +++++--- libavformat/tcp.c | 3 +++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/doc/protocols.texi b/doc/protocols.texi index d3095c88c6..6b5a9cfbd5 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -843,6 +843,11 @@ URL to player swf file, compute hash/size automatically. @item rtmp_tcurl URL of the target stream. Defaults to proto://host[:port]/app. +@item tcp_nodelay=@var{1|0} +Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0. + +@emph{Remark: Writing to the socket is currently not optimized to minimize system calls and reduces the efficiency / effect of TCP_NODELAY.} + @end table For example to read with @command{ffplay} a multimedia resource named diff --git a/libavformat/rtmppkt.c b/libavformat/rtmppkt.c index 00eb0873b2..4b97c0833f 100644 --- a/libavformat/rtmppkt.c +++ b/libavformat/rtmppkt.c @@ -374,6 +374,12 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, prev_pkt[pkt->channel_id].ts_field = pkt->ts_field; prev_pkt[pkt->channel_id].extra = pkt->extra; + // FIXME: + // Writing packets is currently not optimized to minimize system calls. + // Since system calls flush on exit which we cannot change in a system-independant way. + // We should fix this behavior and by writing packets in a single or in as few as possible system calls. + // Protocols like TCP and RTMP should benefit from this when enabling TCP_NODELAY. + if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0) return ret; written = p - pkt_hdr + pkt->size; diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 5a540e3240..b14d23b919 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -123,6 +123,7 @@ typedef struct RTMPContext { int listen_timeout; ///< listen timeout to wait for new connections int nb_streamid; ///< The next stream id to return on createStream calls double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero) + int tcp_nodelay; ///< Use TCP_NODELAY to disable Nagle's algorithm if set to 1 char username[50]; char password[50]; char auth_params[500]; @@ -2653,10 +2654,10 @@ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **o port = RTMP_DEFAULT_PORT; if (rt->listen) ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, - "?listen&listen_timeout=%d", - rt->listen_timeout * 1000); + "?listen&listen_timeout=%d&tcp_nodelay=%d", + rt->listen_timeout * 1000, rt->tcp_nodelay); else - ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); + ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, "?tcp_nodelay=%d", rt->tcp_nodelay); } reconnect: @@ -3115,6 +3116,7 @@ static const AVOption rtmp_options[] = { {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, + {"tcp_nodelay", "Use TCP_NODELAY to disable Nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC|ENC}, {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, { NULL }, }; diff --git a/libavformat/tcp.c b/libavformat/tcp.c index 2198e0f00e..1c19aed887 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -135,6 +135,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { s->listen_timeout = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "tcp_nodelay", p)) { + s->tcp_nodelay = strtol(buf, NULL, 10); + } } if (s->rw_timeout >= 0) { s->open_timeout =