现在很多直播都用到RTMP来传输,而接收RTMP用FFmpeg比较常见(当然也有用其他库的)。FFmpeg对RTMP接收有比较完善实现了,API使用方法也很简单,大多数流程跟文件流处理一样,但是一些区别的地方。下面大概说一下用FFmpeg怎么实现RTMP接收功能,后面再附上封装类的代码。
1. 初始化和打开流。
这是第一步要做的工作,打开了流后才能往下接收数据,打开流需要调用FFmpeg的API avformat_open_input函数,这个函数连接网络的时候会阻塞的,所以要设置超时值,否则有时候会阻塞很久时间。怎么设置超时时间?
AVDictionary* options = nullptr;
av_dict_set(&options, "stimeout", "3000000", 0); //设置超时断开连接时间
上面两行代码设置了连接的超时时间为3秒,但是我试过了,到了超时时间函数还没有返回,好像是FFmpeg的问题。但没有关系,另外我们还有一种方法检测超时,就是通过异常回调函数,avformat_open_input函数可以传入一个回调函数地址作为参数,如果发生连接超时、接收超时,可以直接在回调函数里通知,这样可以使avformat_open_input函数马上返回,避免阻塞太久。
下面是打开流的代码:
BOOL RtmpStreamSession::openInputStream()
{
int res = 0;
bool bIsNetPath = false;
if(_strnicmp(m_InputUrl.c_str(), "rtsp://", 7) == 0 || _strnicmp(m_InputUrl.c_str(), "RTSP://", 7) == 0)
{
bIsNetPath = true;
}
else if(_strnicmp(m_InputUrl.c_str(), "rtmp://", 7) == 0 || _strnicmp(m_InputUrl.c_str(), "RTMP://", 7) == 0)
{
bIsNetPath = true;
}
else
{
bIsNetPath = false;
}
if(bIsNetPath) //从网络接收
{
//Initialize format context
m_inputAVFormatCxt = avformat_alloc_context();
//Initialize intrrupt callback
AVIOInterruptCB icb = {interruptCallBack,this};
m_inputAVFormatCxt->interrupt_callback = icb;
}
m_dwLastRecvFrameTime = 0;
m_dwStartConnectTime = GetTickCount();
//m_inputAVFormatCxt->flags |= AVFMT_FLAG_NONBLOCK;
AVDictionary* options = nullptr;
av_dict_set(&options, "stimeout", "3000000", 0); //设置超时断开连接时间
//m_inputAVFormatCxt->max_analyze_duration = 2000000;
// m_inputAVFormatCxt->fps_probe_size = 30;
res = avformat_open_input(&m_inputAVFormatCxt, m_InputUrl.c_str(), 0, &options);
if(res < 0)
{
string strError = "