当前位置:网站首页>FFmpeg Huaping solution (modify source code, discard incomplete frames)
FFmpeg Huaping solution (modify source code, discard incomplete frames)
2022-08-10 17:49:00 【Audio and video development LaoJiu】
linux下模拟丢帧的命令,因为帧之间的参考关系,实测如果是1%几乎没有完好的帧.
sudo tc qdisc add dev enp0s31f6 root netem loss 0.1%
删除上面的设置
sudo tc qdisc del dev enp0s31f6 root
在头文件libavformat/avformat.h中av_read_frame函数后添加av_deviser_flag函数:
//extern int deviser_flag;
int av_read_frame(AVFormatContext *s, AVPacket *pkt);
int av_deviser_flag();
在头文件libavformat/utils.c ff_read_packet函数前添加int deviser_flag = 666666;
int deviser_flag = 666666;
int av_deviser_flag()
{
return deviser_flag;
}
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
同样在这个头文件中,ff_read_packet函数内添加deviser_flag = 666666;,这个函数是被av_read_frame函数调用的,可以看出这个函数内循环读取pkt,并对pkt处理.
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, i, err;
AVStream *st;
pkt->data = NULL;
pkt->size = 0;
av_init_packet(pkt);
for (;;) {
deviser_flag = 666666;
AVPacketList *pktl = s->internal->raw_packet_buffer;
const AVPacket *pkt1;
同样在这个头文件中,ff_read_packet函数内添加deviser_flag = 111111;
注意看这段函数检测包是否完整,也就是AV_PKT_FLAG_CORRUPT这个标记.还有一个标记可以了解一下AVFMT_FLAG_DISCARD_CORRUPT,这个标记是在av_dict_set(&options, “fflags”, “discardcorrupt”, 0);时添加到流的,这段代码的意思如果丢包了,并且添加了discardcorrupt的fflags那么这个包直接丢弃,不会被av_read_frame函数取出来.实测下面的pkt只包含一帧视频帧.用命令行设置的话,就是-fflags discardcorrupt.
if (pkt->flags & AV_PKT_FLAG_CORRUPT) {
av_log(s, AV_LOG_WARNING,
"Packet corrupt (stream = %d, dts = %s)",
pkt->stream_index, av_ts2str(pkt->dts));
deviser_flag = 111111;
if (s->flags & AVFMT_FLAG_DISCARD_CORRUPT) {
av_log(s, AV_LOG_WARNING, ", dropping it.\n");
av_packet_unref(pkt);
continue;
}
av_log(s, AV_LOG_WARNING, ".\n");
}
因此在我们的代码中在av_read_frame函数后:
if ((av_deviser_flag()) == 111111)
{
//丢弃这帧视频,如果是参考帧(I和P帧),后续的gop帧都要丢掉,直到下个I帧到来.如果是B帧的话,直接丢弃就好.
}
这样再解码测试,还有花屏,看到ffmpeg报的错误是解码错误,推测这是因为不是所有的不完整帧ffmpeg都能检测出来,导致一些不完整帧解码时出错导致.
根据出错的地方打印日志:
在AVFrame结构体中有这个一个标志,专门记录这一帧在解码时出的错误,并不是就解码出错这帧就解不出来了,和其正常帧一样出来,只是做了记录.
/**
* decode error flags of the frame, set to a combination of
* FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there
* were errors during the decoding.
* - encoding: unused
* - decoding: set by libavcodec, read by user.
*/
int decode_error_flags;
#define FF_DECODE_ERROR_INVALID_BITSTREAM 1
#define FF_DECODE_ERROR_MISSING_REFERENCE 2
#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4
#define FF_DECODE_ERROR_DECODE_SLICES 8
经过实测,不仅这几个,decode_error_flags为12时也是解码出错,正确时decode_error_flags为0.
这些记录标志的代码在下面文件中.
libavcodec/h264_slice.c
libavcodec/h264_parse.c
libavcodec/error_resilience.c
libavcodec/h264_cabac.c
打印日志发现每次花屏都是I帧解码出错,并且这时decode_error_flags为4或12,因此这个I帧和后面的gop都需要丢掉.
if(ic->streams[video_index]->codec->codec_id == AV_CODEC_ID_H264 && this->frame_v->key_frame && (this->frame_v->decode_error_flags == 12 || this->frame_v->decode_error_flags == 4))
{
//丢帧,直到下个无错的I帧到,这里是h264解码.
}
重新编译ffmpeg,到这里测试发现视频虽然卡顿但不会花屏了,以上h264The frame structure isI和P,不包含B帧.
如果使用h265时,解码错误,but not recordedAVFrame的decode_error_flags中,This needs to be recorded in the source code yourself,可以使用下面的方法.
在libavcodec/avcodec.h头文件中添加:
extern int deviser_1;
int av_deviser_1();
int av_set_deviser_1(int temp_pram);
在libavcodec/h264_parse.c //定义全局变量av_set_deviser_1,和函数
int av_deviser_1()
{
return deviser_1;
}
int deviser_1 = 666666;
int av_set_deviser_1(int temp_pram)
{
deviser_1 = temp_pram;
return deviser_1;
}
int ff_h264_check_intra4x4_pred_mode(int8_t *pred_mode_cache, void *logctx,
int top_samples_available, int left_samples_available)
同样的文件里,在ff_h264_check_intra4x4_pred_mode函数中,也有一个花屏常见的错误,left block unavailable for requested intra4x4 mode,例如你想在这里做个标记,添加deviser_1 = 222222;
if (status < 0) {
av_log(logctx, AV_LOG_ERROR,
"left block unavailable for requested intra4x4 mode %d\n",
status);
deviser_1 = 222222;
return AVERROR_INVALIDDATA;
}
那么在avcodec_receive_frame函数得到解码数据后检查:
if (av_deviser_1() == 555555)
{
//处理
}
同时处理后应该在下次解码前复位标志,因为这个函数是在解码时调用的:
av_set_deviser_1(666666);
如果在libavcodec文件价内其他文件标记,只需要包含avcodec.h,然后直接使用deviser_1变量即可.注意不可非libavcodec模块内使用全局变量因为编译时不再同一个.so文件中,访问不到.
ic->flags |= AVFMT_FLAG_NOBUFFER;
re = avformat_find_stream_info(ic, NULL);
There are also sometimes incomplete frames in the stream detection stage,This part of the frame needs to be discarded,cannot be placed in the receive buffer,因此需要加上AVFMT_FLAG_NOBUFFER.
同时需要注意h265Some codestream structures such as GPB模式,avformat_open_input函数打开
在h265帧结构为I和P,不含B,以及含I,P,BBut closedGOP时可用,If it is in low latency modeGPB(广义B帧,Refer to the picture at the end of the text for the frame structure),No feasible method has yet been found.
附录用ffplay播放花屏时常见报错:
libavcodec/h264_parse.c
[h264 @ 0x7f8af0045780] left block unavailable for requested intra mode 111111
libavcodec/h264_parse.c
left block unavailable for requested intra4x4 mode 222222
//libavcodec/h264_slice.c
[h264 @ 0x7f8af0045780] error while decoding MB 0 30, bytestream 80303 333333
libavcodec/error_resilience.c
[h264 @ 0x7f8af0045780] concealing 4609 DC, 4609 AC, 4609 MV errors in I frame 444444
libavcodec/h264_cabac.c
[h264 @ 0x7fa298c462c0] cabac decode of qscale diff failed at 62 59 555555 这个目前没见到
[hevc @ 0x7fcc0cb82b40] The cu_qp_delta 52 is outside the valid range [-26, 25]. 这个解码出来花屏
[mpegts @ 0x7fcc0c000940] Packet corrupt (stream = 0, dts = 47665500).
[mpegts @ 0x7fcc0c000940] PES packet size mismatch
libavcodec/hevc_refs.c
[hevc @ 0x7fcc0c59dc00] Could not find ref with POC 14052 //999999
[hevc @ 0x7fcc0c57cc40] CABAC_MAX_BIN : 7
[NULL @ 0x7f3ef02d1500] Invalid NAL unit 35, skipping.
send_error
/usr/app/EncParams/enc_2160p_422_10_50_swap_sq_2chaac/EHParam.sh
设备密码:root hotdog
–enable-parser=hevc
libavformat/hevcdec.c probe
libavcodec/hevcdec.c
-=-=-=HEVC_NAL_SPS
hevc_refs.c 里面
add_candidate_ref 函数
if(!ref){
//return AV_ERROR_INVALIDDATE;
//Error correction is not generated below,就不会错了,注释掉下面的,直接返回,It won't be grey
ret = generate_missing_ref(s,poc);
if(!ref)
return AVERROR(ENOMEM);
}
本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击领取↓↓
边栏推荐
猜你喜欢
随机推荐
函数柯里化(curry)
【独立站运营】做社交媒体营销的两大关键点
产品-Axure9英文版,A页面内a1状态跳转B页面的b2状态,(条件跳转状态)
DASCTF2022.07赋能赛 WEB题目复现
【接入指南 之 直接接入】手把手教你快速上手接入HONOR Connect平台(上)
Making Pre-trained Language Models Better Few-Shot Learners
CDH6.3.2之Kerberos安全认证_大数据培训
文件包含漏洞复习总结
skywalking漏洞学习
Trie字典树
Quicker+沙拉查词使用
建筑施工员证怎么考?报名条件及报考时间是什么?
leetcode:339 嵌套列表权重和
Your local docbook2man was found to work with SGML rather than XML
烟雾、空气质量、温湿度…自己徒手做个环境检测设备
pip install fatal error C1083 cannot open include file "io.h" No such file or directory
Talking about Taishan crowdfunding system development technical description and dapp chain crowdfunding system development analysis
机器人控制器编程实践指导书旧版-实践六 LCD液晶显示(点阵)
直播回顾|多云时代,如何建设企业级云管理平台?(附建设指南下载)
leetcode:281. 锯齿迭代器