ffmpeg 切片花屏_FFmpeg相机花屏花图问题解决方法-Go语言中文社区

本文详细介绍了使用FFmpeg处理rtsp连接时遇到的相机花屏问题,包括图像质量、帧率、码率的调整,rtsp传输方式的改变,以及通过增大UDP缓冲区和采用多线程处理来改善花屏现象的方法。同时,文章还提供了自定义AVPacket列表管理类的代码示例,用于存储和处理rtsp码流。
摘要由CSDN通过智能技术生成

FFmpeg相机花图问题解决方法

一、问题现象

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

ab04ee1f22214e7383f1a8962dba71c6.png

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

cc00f66975b068fcab56198afb7eb597.png

二、解决方法

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

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

b23dc3e60a3615106a12c0b1e413a190.png

将图像质量调到最低、帧率调低(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();

}

}

//释放packet

av_free_packet(pPkt);

//释放list

delete pList;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值