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

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
  1. AVDictionary* options = NULL;  
  2. av_dict_set(&options, "rtsp_transport""udp", 0);  
  3. avformat_open_input(&m_pRtspFmt, m_szRtspUrl, NULL, &options);  

tcp方法如下:

[cpp]  view plain  copy
  1. AVDictionary* options = NULL;  
  2. av_dict_set(&options, "rtsp_transport""tcp", 0);  
  3. avformat_open_input(&m_pRtspFmt, m_szRtspUrl, NULL, &options);  


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

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

        打开ffmpeg源码(我的博客里有怎么编译源码 Windows下编译FFmpeg详解_ffmpeg windows编译_zhouyongku的博客-CSDN博客 )udp.c,可以做这样的实验 在方法2用udp传输的情况下 将udp.c中的UDP_MAX_PKT_SIZE 缩小10倍,再将编译好的ffmpeg库拿来用,则会发现花屏更加剧烈。于是将UDP_MAX_PKT_SIZE放大10倍,则基本上很难再出现花屏现象。

[cpp]  view plain  copy
  1. #define UDP_TX_BUF_SIZE 32768  
  2. #define UDP_MAX_PKT_SIZE (65536*10)  
  3. #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
  1. /******************************************************************* 
  2. * @版权信息: 
  3. * @文件名称:PacketList.h 
  4. * @摘    要:AVPacket列表管理类 
  5. * @作    者:周勇 
  6. * @当前版本:1.0.0 
  7. * @日    期:2015年4月2日 
  8. * @备    注:动态内存加载和释放 
  9. *******************************************************************/  
  10. #include "Common.h"  
  11. class CPacketList  
  12. {  
  13. public:  
  14.     CPacketList();  
  15.     ~CPacketList();  
  16. public:  
  17.     BOOL InputPacket(AVPacket *pktIn);  
  18.     AVPacketList* GetPacket();  
  19.     void FreeAllPacket();  
  20. protected:  
  21.     AVPacketList        *m_pHead;                                           //列表头  
  22.     AVPacketList        *m_pLast;                                               //列表尾  
  23.     UINT                    m_nItemCnt;                                         //共有多少未读项  
  24.     UINT                    m_nInputNum;  
  25.     UINT                    m_nOutputNum;  
  26.     CRITICAL_SECTION    m_cs;  
  27. };  
[cpp]  view plain  copy
  1. #include "PacketList.h"  
  2.   
  3.   
  4. CPacketList::CPacketList()  
  5. {  
  6.     m_pHead = NULL;  
  7.     m_pLast = NULL;  
  8.     m_nItemCnt = 0;  
  9.     m_nInputNum = 0;  
  10.     m_nOutputNum = 0;  
  11.     InitializeCriticalSection(&m_cs);  
  12. }  
  13.   
  14.   
  15. CPacketList::~CPacketList()  
  16. {  
  17. }  
  18. BOOL CPacketList::InputPacket(AVPacket *pktIn)  
  19. {  
  20.     BOOL bRet = TRUE;  
  21.   
  22.     EnterCriticalSection(&m_cs);  
  23.   
  24.     if (m_nItemCnt <= PKT_QUE_SIZE)  
  25.     {  
  26.         AVPacketList *pList = new  AVPacketList;  
  27.   
  28.         av_copy_packet(&pList->pkt, pktIn);  
  29.         pList->next = NULL;  
  30.         m_nItemCnt++;  
  31.   
  32.         if (NULL == m_pHead)  
  33.         {  
  34.             m_pHead = pList;  
  35.         }  
  36.   
  37.         if (m_pLast)  
  38.         {  
  39.             m_pLast->next = pList;  
  40.         }  
  41.         m_pLast = pList;  
  42.         m_nInputNum++;  
  43.     }  
  44.     else  
  45.     {  
  46.         //FreeAllPacket();  
  47.         bRet = FALSE;  
  48.     }  
  49.   
  50.     LeaveCriticalSection(&m_cs);  
  51.   
  52.   
  53.     return bRet;  
  54. }  
  55. AVPacketList* CPacketList::GetPacket( )  
  56. {  
  57.     AVPacketList *pPkt = NULL;  
  58.   
  59.     int nPos = 0;  
  60.   
  61.     EnterCriticalSection(&m_cs);  
  62.       
  63.     if (m_nItemCnt&&m_pHead)  
  64.     {  
  65.         pPkt = m_pHead;  
  66.   
  67.         if (pPkt == m_pLast)  
  68.         {  
  69.             m_pLast = NULL;  
  70.         }  
  71.         m_pHead = pPkt->next;  
  72.         m_nItemCnt--;  
  73.         m_nOutputNum++;  
  74.     }  
  75.   
  76.       
  77.     LeaveCriticalSection(&m_cs);  
  78.     return pPkt;  
  79. }  
  80. void CPacketList::FreeAllPacket()  
  81. {  
  82.     EnterCriticalSection(&m_cs);  
  83.     AVPacketList *pNext = NULL;  
  84.     while (m_pHead)  
  85.     {  
  86.         pNext = m_pHead->next;  
  87.         av_free_packet(&m_pHead->pkt);  
  88.         delete m_pHead;  
  89.         m_pHead = pNext;  
  90.     }  
  91.     m_pLast = NULL;  
  92.     m_nItemCnt = 0;  
  93.     LeaveCriticalSection(&m_cs);  
  94.   
  95. }  

用法:

[cpp]  view plain  copy
  1. CPacketList                 m_pktList;  
  2. //读取rtsp码流线程  
  3. void CIPCamera::ReadStream()  
  4. {  
  5.     AVPacket pkt;  
  6.     av_init_packet(&pkt);  
  7.   
  8.     if (0 == av_read_frame(m_pRtspFmt, &pkt))  
  9.     {  
  10.         if (m_nInViStreamIdx == pkt.stream_index)  
  11.         {  
  12.             //将读取到的视频包存入队列  
  13.             if (!m_pktList.InputPacket(&pkt))  
  14.             {  
  15.                 LOG(LOG_ERROR, "Channel[0x%x]CIPCamera::RreadStream to inputpacket failed of buffer buff!"this, m_nChannelID);  
  16.             }  
  17.         }  
  18.     }  
  19.     av_free_packet(&pkt);  
  20. }  
  21. //从视频包队列中取包进行解码  
  22. void CIPCamera::DecodeStream()  
  23. {  
  24.     AVPacketList *pList = NULL;  
  25.     AVPacket        *pPkt = NULL;  
  26.     pList = m_pktList.GetPacket();  
  27.     if (pList)  
  28.     {  
  29.         pPkt = &pList->pkt;  
  30.         //读取到的是视频包  
  31.         if (m_nInViStreamIdx == pPkt->stream_index)  
  32.         {  
  33.             //解码  
  34.             if (DecodePacket(pPkt, m_pavfrm))  
  35.             {  
  36.                 SendToUser();  
  37.             }  
  38.         }  
  39.         //释放packet  
  40.         av_free_packet(pPkt);  
  41.         //释放list  
  42.         delete pList;  
  43.     }  
  44. }  
转自:http://blog.csdn.net/zhouyongku/article/details/44979159
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值