avformat_open_input打开不存在的rtsp阻塞

发布时间 2023-04-12 16:15:04作者: DoubleLi

网上很多文章,说到avformat_open_input阻塞,就设置一下

av_dict_set(&avdic, "stimeout ", "300000", 0);
 

ffmpeg源码rtsp.c有这样一段定义

 
 
{ "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 },
 
{ "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
 
 

按照正常的说法,应该没问题,但就是不行,设置了还是会一直阻塞。

不管那么多,下面是正解,需要设置一下回调函数。部分关键代码

 
 
// C++ Header
 
 
 
#ifdef __cplusplus
 
extern "C" {
 
#endif
 
 
 
#include <libavformat/avformat.h>
 
#include <libavfilter/avfiltergraph.h>
 
#include <libavfilter/buffersink.h>
 
#include <libavfilter/buffersrc.h>
 
#include <libavutil/opt.h>
 
#include <libavutil/time.h>
 
#ifdef __cplusplus
 
}
 
#endif
 
 
 
...
 
class CFfmpegCapture
 
{
 
private:
 
static int decode_interrupt_cb(void *ctx);
 
//
 
int64_t m_nStartOpenTS = 0;
 
}
 
 
 
//c++ body
 
int CFfmpegCapture::decode_interrupt_cb(void *ctx)
 
{
 
CFfmpegCapture *pThis = (CFfmpegCapture*)ctx;
 
//microseconds 微秒
 
int64_t nDurTime = av_gettime() - pThis->m_nStartOpenTS;
 
if (nDurTime > 3000000 && pThis->m_nStartOpenTS>0)
 
{
 
return 1;
 
}
 
return 0;
 
}
 
 
 
 
 
int CFfmpegCapture::StartCapture(const char *pUrl)
 
{
 
AVDictionary* avdic = NULL;
 
av_dict_set(&avdic, "rtsp_transport", "tcp", 0);
 
//set timeout (in microseconds) of socket TCP I/O operations
 
av_dict_set(&avdic, "stimeout ", "300000", 0);
 
//set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)
 
//av_dict_set(&avdic, "timeout ", "2", 0);
 
 
 
m_pFmtCtx->interrupt_callback.callback = decode_interrupt_cb;
 
m_pFmtCtx->interrupt_callback.opaque = (void*)this;
 
m_nStartOpenTS = av_gettime();
 
 
 
int ret = -1;
 
ret = avformat_open_input(&m_pFmtCtx, pUrl, nullptr, &avdic);
 
if (ret != 0) {
 
return -1;
 
}
 
//成功open以后,置0
 
m_nStartOpenTS = 0;
 
}
 

回调函数返回1表示不在阻塞( If the callback returns 1, the  blocking operation will be aborted.)

ffmpeg-》avio.h文件描述:

 
 
/**
 
* Callback for checking whether to abort blocking functions.
 
* AVERROR_EXIT is returned in this case by the interrupted
 
* function. During blocking operations, callback is called with
 
* opaque as parameter. If the callback returns 1, the
 
* blocking operation will be aborted.
 
*
 
* No members can be added to this struct without a major bump, if
 
* new elements have been added after this struct in AVFormatContext
 
* or AVIOContext.
 
*/
 
typedef struct AVIOInterruptCB {
 
int (*callback)(void*);
 
void *opaque;
 
} AVIOInterruptCB;
 
 
 
//其实ffmpeg从4.0开始不用stimeout,用的listen_timeout等待网络超时,不然会一直超时下去。
 
 
AVDictionary* options = nullptr;
 
//实时播放使用udp,减小带宽并防止断线
 
av_dict_set(&options, "rtsp_transport", "udp", 0);
 
//等待3秒超时
 
av_dict_set(&options, "listen_timeout", "3", 0);