FFmpeg如何设置RTMP的超时时间

FFmpeg有两种方式控制IO退出:

  1. 设置超时时间timeout
  2. 传一个“AVIOInterruptCB”给AVFormatContext,在callback里返回1来让IO退出

两种方式并不是非此即彼,可以结合使用:

1. 超时时间用于读不到数据时的主动退出

2. callback方式用于响应用户的请求,比如用户停止播放时,终止拉流

RTMP是否支持配置timeout,可以看下帮助:

$ ffmpeg -hide_banner  -h protocol=rtmp
...
  -rtmp_tcurl        <string>     ED......... URL of the target stream. Defaults to proto://host[:port]/app.
  -rtmp_listen       <int>        .D......... Listen for incoming rtmp connections (from INT_MIN to INT_MAX) (default 0)
  -listen            <int>        .D......... Listen for incoming rtmp connections (from INT_MIN to INT_MAX) (default 0)
  -timeout           <int>        .D......... Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1 (from INT_MIN to INT_MAX) (default -1)
...

可以看到,RTMP有个timeout配置,但是含义却是listen模式accept()等待的时间,即server模式等待client连接的时间。RTMP的timeout不是作为client的读写超时时间。

再看下TCP:

$ ffmpeg -hide_banner  -h protocol=tcp
tcp AVOptions:
  -listen            <int>        ED......... Listen for incoming connections (from 0 to 2) (default 0)
  -timeout           <int>        ED......... set timeout (in microseconds) of socket I/O operations (from -1 to INT_MAX) (default -1)
  -listen_timeout    <int>        ED......... Connection awaiting timeout (in milliseconds) (from -1 to INT_MAX) (default -1)
  • TCP的timeout是read、write、connect的超时时间,不是listen accept的超时时间
  • TCP的timeout时间单位是微秒
  • TCP的listen_timeout含义和RTMP的timeout含义一样,单位不同

由此可见FFmpeg protocol timeout相关配置有多混乱。问题来了:

  1.  配置RTMP timeout,会传递到TCP的timeout吗?答案是不能。框架层不会自动传递参数给更底层的协议,每个协议负责向下层传递参数。
  2. 能改成RTMP timeout透传给TCP timeout吗?不能,两者含义不一样,单位不一样。如果直接改RTMP timeout配置的含义,会带来向下兼容的问题。

怎么解决RTMP读写无法配置timeout的问题呢?

一种思路是RTMP里加个新的参数配置作为读写timeout,再传给TCP。

实际上,大家往往忽略了,libavformat里的传输协议都有个公共的读写超时时间:

URLContext AVOptions:
  -protocol_whitelist <string>     .D......... List of protocols that are allowed to be used
  -protocol_blacklist <string>     .D......... List of protocols that are not allowed to be used
  -rw_timeout        <int64>      ED......... Timeout for IO operations (in microseconds) (from 0 to I64_MAX) (default 0)

这个配置是否有效果,取决于具体的协议。对于RTMP来说,它收到了rw_timeout的配置,但没有进一步传递给更底层的协议。

所以,支持RTMP读写配置,最简单的做法是透传rw_timeout:


diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 98718bc6da..a0c6195eb2 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -2635,6 +2635,9 @@ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **o
 
     if (rt->listen_timeout > 0)
         rt->listen = 1;
+    /* Pass rw_timeout to underlying transport protocol */
+    if (s->rw_timeout > 0)
+        av_dict_set_int(opts, "rw_timeout", s->rw_timeout, 0);
 
     rt->is_input = !(flags & AVIO_FLAG_WRITE);

细心的同学可能会发现,配置通用的rw_timeout参数,与TCP的timeout参数,还是有不同的地方:

  1. TCP的timeout同时用于open connect、read、write
  2. rw_timeout仅用于read write(如它的名字)

如果把RTMP的rw_time配置,传递给TCP的timeout,涵义上说不通。所以上面patch遗留的问题是RTMP over TCP connect没法配置超时(FFmpeg TCP connect默认5秒超时)。话说回来,connect和read write共用相同的timeout值得商榷。兴趣到此为止,我不打算往下深究了。

作者:quink
来源:Fun With FFmpeg
原文:https://mp.weixin.qq.com/s/IzPpnTh-hdGpQDtqYzxEsQ

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论