您的位置:首页 > 其它

FFmpeg相机花屏花图问题解决方法

2017-05-23 12:39 295 查看


FFmpeg相机花图问题解决方法


一、问题现象

使用FFmpeg进行进行相机rtsp连接获取相机码流并解码在本地显示,这个过程中有遇见相机花图等问题,排查后发现有花图。正常情况下图像为



 

出现花图的情况时图像如下:




二、解决方法


1、设置相机参数--将影响网络传输和解码依赖性的参数都调低

拿海康相机为例:网页登陆相机192.168.1.252 输入默认用户名:admin密码:12345之后,登陆相机,选择“配置”->音视频 设置参数



 

将图像质量调到最低、帧率调低(25修改为12或8)、码率上限(最好为2MB以下)


2、修改rtsp连接方式

rtsp传输有以下几种方式:

UDP传输:Transport:RTP/AVP

TCP传输:Transport:RTP/AVP/TCP

RAW UDP传输:Transport:RAW/RAW/UDP

ffmpeg提供udp和tcp的支持

udp方法如下:

[cpp] view
plain copy

AVDictionary* options = NULL;  

av_dict_set(&options, "rtsp_transport", "udp", 0);  

avformat_open_input(&m_pRtspFmt, m_szRtspUrl, NULL, &options);  

tcp方法如下:

[cpp] view
plain copy

AVDictionary* options = NULL;  

av_dict_set(&options, "rtsp_transport", "tcp", 0);  

avformat_open_input(&m_pRtspFmt, m_szRtspUrl, NULL, &options);  

将连接修改为tcp连接 则能减少花屏,但会有一定程度上的卡顿。


3、增加udp连接方式缓冲区减少丢包

        打开ffmpeg源码(我的博客里有怎么编译源码 http://blog.csdn.net/zhouyongku/article/details/44961447 )udp.c,可以做这样的实验
在方法2用udp传输的情况下 将udp.c中的UDP_MAX_PKT_SIZE 缩小10倍,再将编译好的ffmpeg库拿来用,则会发现花屏更加剧烈。于是将UDP_MAX_PKT_SIZE放大10倍,则基本上很难再出现花屏现象。

[cpp] view
plain copy

#define UDP_TX_BUF_SIZE 32768  

#define UDP_MAX_PKT_SIZE (65536*10)  

#define UDP_HEADER_SIZE 8  


 4、多线程处理

        测试过av_read_frame的耗时-发现在25帧/秒 4M比特流的情况下,av_read_frame耗时30~40ms,而解码也需要10ms左右,这就决定了1秒以内难以完成读取视频和解码视频的操作,即便是缓冲也不行,因为平均时间=25*(30~40+10)>1000ms。所以需要将读取rtsp码流作为一个线程,解码作为一个线程。下面是我封装好的存储rtsp线程码流的类

[cpp] view
plain copy

/******************************************************************* 

* @版权信息: 

* @文件名称:PacketList.h 

* @摘    要:AVPacket列表管理类 

* @作    者:周勇 

* @当前版本:1.0.0 

* @日    期:2015年4月2日 

* @备    注:动态内存加载和释放 

*******************************************************************/  

#include "Common.h"  

class CPacketList  

{  

public:  

    CPacketList();  

    ~CPacketList();  

public:  

    BOOL InputPacket(AVPacket *pktIn);  

    AVPacketList* GetPacket();  

    void FreeAllPacket();  

protected:  

    AVPacketList        *m_pHead;                                           //列表头  

    AVPacketList        *m_pLast;                                               //列表尾  

    UINT                    m_nItemCnt;                                         //共有多少未读项  

    UINT                    m_nInputNum;  

    UINT                    m_nOutputNum;  

    CRITICAL_SECTION    m_cs;  

};  

[cpp] view
plain copy

#include "PacketList.h"  

  

  

CPacketList::CPacketList()  

{  

    m_pHead = NULL;  

    m_pLast = NULL;  

    m_nItemCnt = 0;  

    m_nInputNum = 0;  

    m_nOutputNum = 0;  

    InitializeCriticalSection(&m_cs);  

}  

  

  

CPacketList::~CPacketList()  

{  

}  

BOOL CPacketList::InputPacket(AVPacket *pktIn)  

{  

    BOOL bRet = TRUE;  

  

    EnterCriticalSection(&m_cs);  

  

    if (m_nItemCnt <= PKT_QUE_SIZE)  

    {  

        AVPacketList *pList = new  AVPacketList;  

  

        av_copy_packet(&pList->pkt, pktIn);  

        pList->next = NULL;  

        m_nItemCnt++;  

  

        if (NULL == m_pHead)  

        {  

            m_pHead = pList;  

        }  

  

        if (m_pLast)  

        {  

            m_pLast->next = pList;  

        }  

        m_pLast = pList;  

        m_nInputNum++;  

    }  

    else  

    {  

        //FreeAllPacket();  

        bRet = FALSE;  

    }  

  

    LeaveCriticalSection(&m_cs);  

  

  

    return bRet;  

}  

AVPacketList* CPacketList::GetPacket( )  

{  

    AVPacketList *pPkt = NULL;  

  

    int nPos = 0;  

  

    EnterCriticalSection(&m_cs);  

      

    if (m_nItemCnt&&m_pHead)  

    {  

        pPkt = m_pHead;  

  

        if (pPkt == m_pLast)  

        {  

            m_pLast = NULL;  

        }  

        m_pHead = pPkt->next;  

        m_nItemCnt--;  

        m_nOutputNum++;  

    }  

  

      

    LeaveCriticalSection(&m_cs);  

    return pPkt;  

}  

void CPacketList::FreeAllPacket()  

{  

    EnterCriticalSection(&m_cs);  

    AVPacketList *pNext = NULL;  

    while (m_pHead)  

    {  

        pNext = m_pHead->next;  

        av_free_packet(&m_pHead->pkt);  

        delete m_pHead;  

        m_pHead = pNext;  

    }  

    m_pLast = NULL;  

    m_nItemCnt = 0;  

    LeaveCriticalSection(&m_cs);  

  

}  

用法:

[cpp] view
plain copy

CPacketList                 m_pktList;  

//读取rtsp码流线程  

void CIPCamera::ReadStream()  

{  

    AVPacket pkt;  

    av_init_packet(&pkt);  

  

    if (0 == av_read_frame(m_pRtspFmt, &pkt))  

    {  

        if (m_nInViStreamIdx == pkt.stream_index)  

        {  

            //将读取到的视频包存入队列  

            if (!m_pktList.InputPacket(&pkt))  

            {  

                LOG(LOG_ERROR, "Channel[0x%x]CIPCamera::RreadStream to inputpacket failed of buffer buff!", this, m_nChannelID);  

            }  

        }  

    }  

    av_free_packet(&pkt);  

}  

//从视频包队列中取包进行解码  

void CIPCamera::DecodeStream()  

{  

    AVPacketList *pList = NULL;  

    AVPacket        *pPkt = NULL;  

    pList = m_pktList.GetPacket();  

    if (pList)  

    {  

        pPkt = &pList->pkt;  

        //读取到的是视频包  

        if (m_nInViStreamIdx == pPkt->stream_index)  

        {  

            //解码  

            if (DecodePacket(pPkt, m_pavfrm))  

            {  

                SendToUser();  

            }  

        }  

        //释放packet  

        av_free_packet(pPkt);  

        //释放list  

        delete pList;  

    }  

}  

转自:http://blog.csdn.net/zhouyongku/article/details/44979159
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐