FFmpeg 解码 H.264 视频出现花屏和马赛克的解决办法

FFmpeg 解码 H.264 视频出现花屏和马赛克的解决办法

FFmpeg 解码 H.264 视频出现花屏和马赛克的解决办法

四个可能的原因

  1. 发送数据包太大,超过了 FFmpeg 的默认最大值。
  2. 网络情况较差时,因网络状况出现的丢包。
  3. 解码出错。
  4. 包乱序。

原因一的解决方法

一种方法是控制播放源的发送数据大小,但这极大浪费了当前的网络带宽,非优选方案。

更好的做法是扩大接收端的接收缓冲区,其修改方法为:

在 FFmpeg 的源码中,找到 udp.c 文件并修改 UDP_MAX_PKT_SIZE 默认值。

这里将 UDP_MAX_PKT_SIZE × 10,将缓冲区扩大了10倍。

原因二的解决方法

排查方法:

  1. 设全局变量:在丢包时将全局变量置为不同的值,最后在使用的地方根据全局变量的值来判断该帧是否完整,全局变量可在 FFmpeg 任意的头文件中设置(比如 avcodec.h)。
  2. 修改rtpdec.c文件包含 missed %d package 的地方,这里出现丢包,需修改代码,对帧序号作标记。

在接收端根据RTP包的SeqNumber来判断是否丢包,如果丢包就标记一下。在mark为1或时间戳改变的时候,说明一帧结束了,此时如果标记为丢包了,就扔掉数据,没有丢包就给解码器。如果丢包的帧为I帧,则不仅丢掉当前I帧,此I帧之后的P帧也要丢掉,也就是说在下一个I帧到来之前,所有过来的包都丢掉,然后开始判断收到的RTP包是不是I帧。

判断函数:

cpp 复制代码
static bool isH264iFrame(byte[] paket)
{
	int RTPHeaderBytes = 0;

	int fragment_type = paket[RTPHeaderBytes + 0] & 0x1F;
	int nal_type = paket[RTPHeaderBytes + 1] & 0x1F;
	int start_bit = paket[RTPHeaderBytes + 1] & 0x80;

	if (((fragment_type == 28 || fragment_type == 29) && nal_type == 5 && start_bit == 128) ||
		fragment_type == 5 || fragment_type == 7 || fragment_type == 8)
	{
		return true;
	}

	return false;
}

原因三的解决方法

排查方法:

  1. 设全局变量:在解码出错时将全局变量置为不同的值,最后在使用的地方根据全局变量的值来判断该帧是否完整,全局变量可在 FFmpeg 任意的头文件中设置(比如 avcodec.h)。
  2. 修改error_resilience.c文件 包含concealing %d DC, %d AC, %d MV errors in %c frame的地方。这里出现解包错误,需标记。
  3. 修改h264_cavlc.c文件中包含 Invalid level prefix处 这里出错,需标记。
    修改h264_cavlc.c文件中包含dquant out of range处,出错,需标记。
    修改h264_cavlc.c文件中包含corrupted macroblock处,出错,需标记。
    修改h264_cavlc.c文件中包含negative number of zero coeffs at处,出错,需标记。
    修改h264_cavlc.c文件中包含mb_type %d in %c slice too large at %d %d处,出错,需标记。
    修改h264_cavlc.c文件中包含cbp too large处,出错,需标记。
  4. 修改error_resilience.c文件中包含Cannot use previous picture in error concealment处,出错,需标记。
    修改error_resilience.c文件中包含Cannot use next picture in error concealment处,出错,需标记。
  5. 修改h264.c文件中包含out of range intra chroma pred mode at处,出错,需标记。
    修改h264.c文件中包含top block unavailable for requested intra mode at处,出错,需标记。
    修改h264.c文件中包含left block unavailable for requested intra mode at处,出错,需标记。
  6. 修改h264_slice.c文件中包含error while decoding MB处,出错,需标记。
  7. 修改svq3.c文件中包含error while decoding MB处,出错,需标记。

当我们从网络中接收到RTP包,去了包头,拿到Payload数据之后一般就会送去解码,但是如果直接送去解码器解码,很可能会出现花屏。这个问题我很早就遇到过,当时查阅过资料,发现送给H264解码器的必须是一个NALU单元,或者是完整的一帧数据(包含H264 StartCode),也就是说我们拿到Payload数据之后,还要将分片的数据组成一个NALU或完整的一帧之后才送给解码器。

原因四的解决方法

打印RTP包的SeqNumber看有没有不连续或乱序的问题,如果是用UDP传输,则RTP包容易发生乱序,需要对包按顺序进行重组再解码。

参考

  1. https://blog.csdn.net/zhoubotong2012/article/details/103002257
  2. https://blog.csdn.net/c_base_jin/article/details/106772949
  3. https://blog.csdn.net/sz76211822/article/details/87797475
  4. https://www.ebaina.com/articles/140000016765
相关推荐
换个昵称都难12 小时前
webrtc 音频模块FEC模块
网络·音视频·webrtc
qq_3665665012 小时前
视频配音自动化Pipeline:TTS选型+音色克隆+批量处理(附完整代码)
自动化·新媒体运营·音视频·音频
hz5678917 小时前
公安局远程办案用什么音视频系统?安全取证与多方协同方案
安全·架构·云计算·音视频·实时音视频·信息与通信
Championship.23.2417 小时前
Linux 3.0 音频机制深度解析:ALSA基础架构与传统音频驱动模型
linux·运维·音视频·alsa
VOOHU-沃虎18 小时前
PoE+音频一体化接口设计:从电源变压器到XLR卡侬座的完整链路
音视频
“码”力全开20 小时前
解密企业级智能视频中台:基于 Docker 与边缘计算的 GB28181/RTSP 异构架构设计(支持源码交付)
docker·音视频·边缘计算
潜创微科技20 小时前
QCW5007+QCW5004 | HDMI 1.3 无线投屏芯片方案空旷 150 米支持穿墙传输
音视频
MemoriKu21 小时前
Flutter 相册 APP 视频模态稳定化实战:从视频抽帧、Embedding 元数据到 Android 真机启动修复
android·开发语言·前端·flutter·架构·音视频·embedding
EasyDSS21 小时前
视频直播点播/高清点播/音视频点播/云点播/云直播EasyDSS一站式音视频平台助力智慧校园智能化建设
音视频
johnny23321 小时前
视频创作工具:OpenCut、HyperFrames、social-auto-upload、OpenStoryline、ArcReel
音视频