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

来源:互联网 发布:利用淘宝店信用卡套现 编辑:程序博客网 时间:2024/06/07 03:53

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方法如下:

AVDictionary* options = NULL;av_dict_set(&options, "rtsp_transport", "udp", 0);avformat_open_input(&m_pRtspFmt, m_szRtspUrl, NULL, &options);

tcp方法如下:

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倍,则基本上很难再出现花屏现象。

#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线程码流的类

/******************************************************************** @版权信息:* @文件名称: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;//列表尾UINTm_nItemCnt;//共有多少未读项UINTm_nInputNum;UINTm_nOutputNum;CRITICAL_SECTIONm_cs;};
#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);}

用法:

CPacketListm_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();}}//释放packetav_free_packet(pPkt);//释放listdelete pList;}}


 

1 0
原创粉丝点击