avcodec_send_packet函数阻塞

用ffmpeg4.1.4开发一个播放器,解码过程如下,在每个函数前设置标志,测试发现程序阻塞在avcodec_send_packet函数。

while(true){av_read_frameavcodec_send_packetavcodec_receive_frameav_packet_unref
}

解释如下:

avcodec_send_packetavcodec_receive_frame 的工作原理是,avcodec_send_packet 向解码器发送压缩数据包,而 avcodec_receive_frame 从解码器接收解码后的帧。解码器内部有一个缓冲区,用于存储解码过程中间的数据。如果缓冲区已满(即没有足够的空间来存储新的数据包),avcodec_send_packet 就会阻塞,直到有足够的空间。

我用的是处理器是rk3288,后台打印信息如下:

[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 1615 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 2107 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 2064 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 1504 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 2588 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 1642 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 1721 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Received a frame.
[h264_rkmpp @ 0xa5795e20] Wrote 1437 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2307 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1427 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1638 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2303 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1342 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2193 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1567 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2247 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1396 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2375 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1520 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1663 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2273 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1288 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 2340 bytes to decoder
[h264_rkmpp @ 0xa5795e20] Wrote 1399 bytes to decoder

avcodec_send_packe函数为什么会“get a frame”呢?源码如下,猜测是阻塞到这里

int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
{AVCodecInternal *avci = avctx->internal;int ret;if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))return AVERROR(EINVAL);if (avctx->internal->draining)return AVERROR_EOF;if (avpkt && !avpkt->size && avpkt->data)return AVERROR(EINVAL);av_packet_unref(avci->buffer_pkt);if (avpkt && (avpkt->data || avpkt->side_data_elems)) {ret = av_packet_ref(avci->buffer_pkt, avpkt);if (ret < 0)return ret;}ret = av_bsf_send_packet(avci->filter.bsfs[0], avci->buffer_pkt);if (ret < 0) {av_packet_unref(avci->buffer_pkt);return ret;}if (!avci->buffer_frame->buf[0]) {ret = decode_receive_frame_internal(avctx, avci->buffer_frame);if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)return ret;}return 0;
}static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame)
{int ret;while (!frame->buf[0]) {ret = decode_simple_internal(avctx, frame);if (ret < 0)return ret;}return 0;
}

解决方法:

1、在调用 avcodec_send_packet 之前,可以先调用 avcodec_receive_frame,即使你不确定是否有帧可以接收。这有助于清理缓冲区。

2、在while循环中等待avcodec_receive_frame

    ret = avcodec_send_packet(codec_ctx, packet); while (ret >= 0) {AVFrame *frame = av_frame_alloc();if (!frame) {// 处理内存分配错误return AVERROR(ENOMEM);}ret = avcodec_receive_frame(codec_ctx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {// 没有更多帧可以接收,退出循环av_frame_free(&frame);break;} else if (ret < 0) {// 处理接收帧错误av_frame_free(&frame);return ret;}}

3、正常情况下向解码器发送一包数据会收到一个解码后的帧,因此增加一个检测机制,当多次发送数据包但没有收到解码帧后则重置解码器。

void reset_decoder(AVCodecContext* codecContext) {// 刷新解码器缓冲区avcodec_flush_buffers(codecContext);// 关闭解码器avcodec_close(codecContext);// 重新打开解码器if (avcodec_open2(codecContext, codecContext->codec, nullptr) < 0) {std::cerr << "Could not re-open codec" << std::endl;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/41375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity3D游戏 RPG

丛林探险游戏 人物进行探险游戏 拥有登录&#xff0c;首页&#xff0c;3D物体旋转浏览的功能&#xff0c;还能进行种植树等功能

【matlab 路径规划】基于改进遗传粒子群算法的药店配送路径优化

一 背景介绍 本文分享的是一个基于订单合并的订单分配和路径规划联合优化&#xff0c;主要背景是骑手根据客户需求&#xff0c;从药店取药之后进行配送&#xff0c;配送的过程中考虑路径的长度、客户的服务时间窗、车辆的固定成本等要素&#xff0c;经过建模和优化得到最优的配…

C# WinForm —— 38 SplitContainer介绍

1. 简介 将页面拆分成两个大小可以调整的区域&#xff0c;中间有一个拆分条&#xff0c;可以拖动拆分条来调整左右区域的大小 2. 属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到BoderStyle边框样式&#xff1a;None、FixedSingle、Fixed3DAutoScroll当控件…

C++ 引用做函数返回值

作用&#xff1a;引用是可以作为函数的返回值存在的 注意&#xff1a;不要返回局部变量引用 用法&#xff1a;函数调用作为左值 示例&#xff1a; 运行结果&#xff1a;

程序员熬夜看欧洲杯被“冻住”,呼吸困难……

2024欧洲杯接近尾声&#xff0c;更是激发球迷兴趣。由于时差关系&#xff0c;很多球迷熬夜看球&#xff0c;啤酒、宵夜成了标配。然而&#xff0c;在这份欢乐背后&#xff0c;也隐藏着健康风险。 日前&#xff0c;浙江杭州29岁的程序员单先生熬夜与朋友看完球赛后开车回家&…

零基础STM32单片机编程入门(九)IIC总线详解及EEPROM实战含源码视频

文章目录 一.概要二.IIC总线基本概念1.总体特征2.通讯流程 三.EEPROM介绍1.M24C08基本介绍2.向M24C08写一个字节时序图3.从M24C08读一个字节时序图 四.GPIO模拟IIC驱动M24C08读写五.CubeMX工程源代码下载六.讲解视频链接地址七.小结 一.概要 IIC(Inter&#xff0d;Integrated …

黑马|最新AI+若依 |初识项目

本章主要内容是&#xff1a; 1.快速搭建了若依前后端项目在本地 2.实现了单表的增删改查快速生成 文章目录 介绍1.若依介绍2.若依的不同版本3.项目运行环境 初始化前后端项目1.下载若依项目2.初始化后端a.把表导入到数据库中b.更改application.yml文件 3.初始化前端a.安装依赖…

基于LoFTR_TRT项目实现LoFTR模型的trt推理与onnx推理,3060显卡下320图像30ms一组图

本博文主要记录了使用LoFTR_TRT项目将LoFTR模型导出为onnx模型&#xff0c;然后将onnx模型转化为trt模型。并分析了LoFTR_TRT与LoFTR的基本代码差异&#xff0c;但从最后图片效果来看是与官网demo基本一致的&#xff0c;具体可以查看上一篇博客记录。最后记录了onnx模型的使用【…

WebAssembly场景及未来

引言 从前面的文章中&#xff0c;我们已经了解了 WebAssembly&#xff08;WASM&#xff09; 的基本知识&#xff0c;演进历程&#xff0c;以及简单的使用方法。通过全面了解了WebAssembly的设计初衷和优势&#xff0c;我们接下来要知道在什么样的场景中我们会使用 WASM 呢&…

在门店里造绿色氧吧!康养行业也这么卷了?

拼啥不如拼健康&#xff0c;现在的人算是活明白了&#xff0c;不但中老年人这样想&#xff0c;年轻人也这样干。你可能不知道&#xff0c;现在众多健康养生门店&#xff0c;逐渐成了年轻人“组团养生”的好去处&#xff0c;也是他们吃喝玩乐之外的新兴消费趋势。 而在看得见的…

原理图设计工作平台:capture和capture CIS的区别在于有没有CIS模块

1环境:design entry CIS 2.参数设置命令options——preference&#xff08;7个选项卡colors/print&#xff0c;grid display&#xff0c;miscellaneous&#xff0c;pan and zoom&#xff0c;select&#xff0c;text editor和board simulation&#xff09; 1)颜色设置colors/p…

应急响应--网站(web)入侵篡改指南

免责声明:本文... 目录 被入侵常见现象: 首要任务&#xff1a; 分析思路&#xff1a; 演示案例: IIS&.NET-注入-基于时间配合日志分析 Apache&PHP-漏洞-基于漏洞配合日志分析 Tomcat&JSP-弱口令-基于后门配合日志分析 (推荐) Webshell 查杀-常规后门&…

R语言实战—圆形树状图

话不多说&#xff0c;先看最终效果&#xff1a; 圆形树状图是树状图的一个变型&#xff0c;其实都是层次聚类。 接下来看代码步骤&#xff1a; 首先要先安装两个包&#xff1a; install.packages("ggtree") install.packages("readxl") 咱就别问问什么…

go zero入门

一、goctl安装 goctl 是 go-zero 的内置脚手架&#xff0c;可以一键生成代码、文档、部署 k8s yaml、dockerfile 等。 # Go 1.16 及以后版本 go install github.com/zeromicro/go-zero/tools/goctllatest检查是否安装成功 $ goctl -v goctl version 1.6.6 darwin/amd64vscod…

vue2响应式原理+模拟实现v-model

效果 简述原理 配置对象传入vue实例 模板解析&#xff0c;遍历出所有文本节点&#xff0c;利用正则替换插值表达式为真实数据 data数据代理给vue实例&#xff0c;以后通过this.xxx访问 给每个dom节点增加观察者实例&#xff0c;由观察者群组管理&#xff0c;内部每一个键值…

sqlite 数据库 介绍

文章目录 前言一、什么是 SQLite &#xff1f;二、语法三、SQLite 场景四、磁盘文件 前言 下载 目前已经出到了&#xff0c; Version 3.46.0 SQLite&#xff0c;是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是…

VMware虚拟机配置桥接网络

转载&#xff1a;虚拟机桥接网络配置 一、VMware三种网络连接方式 VMware提供了三种网络连接方式&#xff0c;VMnet0, VMnet1, Vmnet8&#xff0c;分别代表桥接&#xff0c;Host-only及NAT模式。在VMware的编辑-虚拟网络编辑器可看到对应三种连接方式的设置&#xff08;如下图…

Square Root SAM论文原理

文章目录 Square Root SAM论文原理核心原理SLAM问题的3种表示贝叶斯网络因子图&#xff08;Factor graph&#xff09;马尔科夫随机场(Markov Random Field, MRF) SLAM最小二乘问题&线性化因式分解 factorization矩阵与图(Matrices ⇔ Graphs)因式分解&变量消元(Factori…

Kafka系列之Kafka知识超强总结

一、Kafka简介 Kafka是什么 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff08;消息引擎系统&#xff09;&#xff0c;它可以处理消费者在网站中的所有动作流数据。 这种动作&#xff08;网页浏览&#xff0c; 搜索和其他用户的行动&#xff09;是在现代网络上的许多社…

14-22 剑和远方2 - 深度神经网络中的学习机制

概论 在第一部分中&#xff0c;我们深入探讨了人工智能的兴衰简史以及推动人工智能发展的努力。我们研究了一个简单的感知器&#xff0c;以了解其组件以及简单的 ANN 如何处理数据和权重层。在简单的 ANN 中&#xff0c;不会对数据执行特定操作。ANN 中的激活函数是一个线性函…