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,到这里测试发现视频虽然卡顿但不会花屏了,以上h264帧结构是I和P,不包含B帧。

如果使用h265时,解码错误,但并不会记录在AVFrame的decode_error_flags中,这就需要自己在源码中记录了,可以使用下面的方法。

在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);

码流探测阶段也有时有不完整的帧,这部分帧需要舍弃,不能放到接收缓存中,因此需要加上AVFMT_FLAG_NOBUFFER。

同时需要注意h265的一些码流结构如GPB模式,avformat_open_input函数打开

在h265帧结构为I和P,不含B,以及含I,P,B但是闭合GOP时可用,如果是低延时模式GPB(广义B帧,帧结构参考文末图片),目前还未找到可行的方法。

附录用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;
//以下不产生纠错,就不会错了,注释掉下面的,直接返回,就不会灰了
ret = generate_missing_ref(s,poc);
if(!ref)
return AVERROR(ENOMEM);
}

本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs)↓↓↓↓↓↓见下面↓↓文章底部点击领取↓↓

FFmpeg花屏解决(修改源码,丢弃不完整帧)相关推荐

  1. ffmpeg花屏解决(修改源码,丢弃不完整帧和解码错误帧)

    linux下模拟丢帧的命令,因为帧之间的参考关系,实测如果是1%几乎没有完好的帧. tc只能对发出的包做处理,但它还可以做延时抖动处理. sudo tc qdisc add dev enp0s31f6 ...

  2. Python 技术篇 - 修改源码解决中文主机名导致的flask、socket服务起不来问题: ‘utf-8‘ codec can‘t decode byte 0xc0 in position...

    由于主机名为中文导致的 flask 服务起不来,报错如下: File "D:\work\python3.9_64\lib\socket.py", line 791, in getf ...

  3. FFmpeg修改源码支持H265

    文章目录 一. 安装FFmpeg 二. 下载源码 三. 修改源码 四. 重新编译 五.执行 一. 安装FFmpeg 如果已经安装,建议先卸载. brew uninstall ffmpeg 然后用以下命 ...

  4. 计算机毕业设计Java智慧公寓系统演示录屏2021(源码+系统+mysql数据库+Lw文档)

    计算机毕业设计Java智慧公寓系统演示录屏2021(源码+系统+mysql数据库+Lw文档) 计算机毕业设计Java智慧公寓系统演示录屏2021(源码+系统+mysql数据库+Lw文档) 本源码技术栈 ...

  5. Ubuntu 18.04下autoware 1.12 安装日志(含花屏解决方法)

    Ubuntu 18.04下autoware 1.12 安装日志 安装Autoware 1.12 Autoware官网信息 下载相关依赖项 新建文件夹下载autoware 1.12 编译autoware ...

  6. android系统源码7.1.2_r8下载,编译,运行到nexus5X上,修改源码并编译SDK进行测试

    一,学习android系统源码下载,编译的作用 1,可以自己 DIY 自己的rom系统,从系统层面,宏观的加深理解 android系统 2,编译自己的 userdebug(原生root权限) rom, ...

  7. mybatis-generator修改源码2

    参考: MyBatis Generator系列(三)----修改源码实现中文注释 (包括java.net.MalformedURLException at java.net.URL.<init& ...

  8. android注入 定位,[原创]修改源码实现全局(无需root)注入躲开注入检测

    看这篇文章需要的技能 1.会编译android源码(如果你不愿意编译源码,还有另外一种办法,下面我会提供) 2.会使用substrate或者xposed 以上2个网上资料很多我就不啰嗦了 一.市面上目 ...

  9. 黑色响应式全屏滚动主页源码

    介绍: html5黑色大气的个人博客全屏滚动个人主页源码下载,右键记事本即可修改. 网盘下载地址: http://kekewl.cc/ZNE7tnBEfKF0 图片:

最新文章

  1. hdu 4876 ZCC loves cards(暴力)
  2. RDKit:化合物骨架分析
  3. ABAP术语-World Wide Web
  4. 高级转录组分析和R数据可视化第十一期(报名线上课还可免费参加线下课)
  5. 7-13 日K蜡烛图
  6. 【数据结构的魅力】004.堆、前缀树、桶排序、排序算法总结
  7. 【风电功率预测】基于matlab灰狼算法优化LSTM风电功率预测【含Matlab源码 1392期】
  8. #include <iostream> C++ Hello World!
  9. 通信专业综合能力(中级)考试大纲
  10. AWE2020:黄金十年再踏征程,以科技“智竞”未来
  11. 免费的asp.net 2.0空间
  12. 基于51单片机霍尔自行车码表测速系统电路设计(毕业设计资料)
  13. D3 二维图表的绘制系列(十六)矩形树状图
  14. vmware workstation 未能启动vmware
  15. 2021-03-13 大数据课程笔记 day52
  16. Typora的崩溃导致文件丢失
  17. Python写简单的拼图小游戏
  18. flutter 微信语言选择_#Flutter项目(3)之仿写微信通讯录界面
  19. 计算机任务计划程序已损坏,Win7-该任务映像已损坏或已篡改。(异常来自HRESULT:0x80041321)解决办法...
  20. 如何将安卓手机WiFI镜像投屏到电脑

热门文章

  1. 2021年全球刮雨器收入大约5975.4百万美元,预计2028年达到6558.9百万美元
  2. Aliplayer 切换不同格式视频
  3. 时间序列:时间序列模型---自回归过程(AutoRegressive Process)
  4. [内附完整源码和文档] 基于Java的宾馆住宿管理系统
  5. 全新小龟双端影视1.6壳+反编译视频教程
  6. 第十一章:实现SpringBoot单个、多个文件的上传
  7. 基于Qt的QQ局域网聊天
  8. oracle通过表空间文件进行数据库恢复,oracle通过DBF恢复数据
  9. 回顾一下去年定的小目标
  10. php windows vld,PHP安装VLD查看opcode