【音视频开发】 ffmpeg解码API

news2024/11/15 11:06:47

1.版本迭代


ffmpeg解码API经过了好几个版本的迭代,上一个版本的API是

  • 解码视频:avcodec_decode_video2

  • 解码音频:avcodec_decode_audio4

我们现在能看到的很多解码例子用的都是这两个,不过现在ffmpeg更推荐用新一代的API

  • 向解码器输送数据包:avcodec_send_packet

  • 从解码器获取帧:avcodec_receive_frame

通常来说,一个packet会被解码出一个frame,不过也存在一个packet被解码出多个frame或者多个packet才能解码出一个frame的情况,甚至也有些解码器在输入以及输出端上可能会有延迟。因此原来的API在某种程度上存在对调用者误导的可能,使得调用者认为输入的一个或者多个Packet就对应着解码器所输出的一个frame,但实际上可能并非如此。

新的API完全隐藏了“解码”这一概念,只提供一个输入packet的接口以及输出frame的接口,如此一来调用者可以不必了解解码器的具体细节,只需要了解这两个接口的调用规则就能写出适用于所有解码器的代码。

2.状态机


新一代API是一个状态机。调用API是一种动作,API的返回值就是一种状态,通过动作可以进行状态的转换。正常情况下,状态机有6种状态:

send 0

send_packet返回值为0,正常状态,意味着输入的packet被解码器正常接收。

send EAGAIN

send_packet返回值为EAGAIN,输入的packet未被接收,需要输出一个或多个的frame后才能重新输入当前packet。

send EOF

send_packet返回值为EOF,当send_packet输入为NULL时才会触发该状态,用于通知解码器输入packet已结束。

receive 0

receive_frame返回值为0,正常状态,意味着已经输出一帧。

receive EAGAIN

receive_frame返回值为EAGAIN,未能输出frame,需要输入更多的packet才能输出当前frame。

receive EOF

receive_frame返回值为EOF,当处于send EOF状态后,调用一次或者多次receive_frame后就能得到该状态,表示所有的帧已经被输出。

如上图所示,尽管状态转换稍微有些繁琐,但该状态转换图实际上包含了两种策略,对两种策略分别进行分析能对状态机有一个更为清晰的了解。

以消耗packet为主的策略

虽然我们前面说过输入的packet并不一定对应于所输出的frame,不过在这里为了方便语言上的描述,在这里我们可以认为receive_frame是对输入的packet的一种消耗,当receive_frame返回EAGAIN时就认为所输入的packet被完全消耗。这里的策略就是对每次所输入的一个packet,都循环调用receive_frame对该packet进行消耗,直到所输入的packet消耗完成。

在消耗完一个packet后输入下一个packet

当所有的packet都消耗完成后,调用send_packet输入NULL,把状态转换为send EOF,最后调用receive_frame把状态转换为receive EOF即完成所有解码任务。

以获取frame为主的策略

本策略是先循环调用send_packet直到返回EAGAIN,此时肯定可以输出frame了

然后调用receive_frame输出一帧

当所有的packet都输入完成后,调用send_packet输入NULL,把状态转换为send EOF,最后调用receive_frame把状态转换为receive EOF即完成所有解码任务。

3.API代码分析


avcodec_send_packet

avcodec_send_packet有如下结构:

首先粗略了解一下bsf,即bitstream filter。音频与视频编码后数据会以一定的语法结构进行构建,除了编码后的数据之外还有一些并非解码所必须的语法元素,这些语法元素通常只是在解码、显示等过程起到辅助作用,这些语法元素很少使用到,它们的位置一般是位于在编码后的数据之前,如h264中的SEI。bitstream filter就是对这些语法元素进行调整。

av_bsf_send_packet会把packet输送到bitstream filter中,在av_bsf_send_packet当中,会判断用于暂存输入packet的buffer_pkt是否为有效packet,如果是有效packet,则表明上次传入的packet仍未被解码器消耗,因此无法接收这次传入的packet,返回EAGAIN。

if (ctx->internal->buffer_pkt->data ||

ctx->internal->buffer_pkt->side_data_elems)

return AVERROR(EAGAIN);

否则就把当前packet移动到用于暂存的buffer_pkt

av_packet_move_ref(ctx->internal->buffer_pkt, pkt);

decode_receive_frame_internal是实际的解码入口,它有如下结构

decode_receive_frame_internal需要先从用于暂存的buffer_pkt中取出输入的packet,这是调用bsfs_poll来实现的。bsfs_poll会执行所有的bitstream filter,最终会调用到ff_bsf_get_packet_ref,在该函数内,会先判断用于暂存packet的buffer_pkt是否为有效packet,不是则返回EAGAIN

if (!ctx->internal->buffer_pkt->data &&

!ctx->internal->buffer_pkt->side_data_elems)

return AVERROR(EAGAIN);

有效则取出该packet

av_packet_move_ref(pkt, ctx->internal->buffer_pkt);

取出该packet后就可以调用codec的decode函数来进行解码。

总体来看avcodec_send_packet经历了如下流程。

avcodec_receive_frame

avcodec_receive_frame有如下结构:

avcodec_receive_frame会先进行判断,如果解码器解码出了一帧,则会调用av_frame_move_ref输出这一帧,否则继续调用decode_receive_frame_internal继续进行解码。

if (avci->buffer_frame->buf[0]) {

av_frame_move_ref(frame, avci->buffer_frame);

} else {

ret = decode_receive_frame_internal(avctx, frame);

if (ret < 0)

return ret;

}

总体来说avcodec_receive_frame经历了如下流程。

关于EAGAIN

我们前面讨论过EAGAIN状态:

  • avcodec_send_packet返回EAGAIN表明无法输入当前packet,需要调用avcodec_receive_frame进行消耗上一个packet。

  • avcodec_receive_packet返回EAGAIN表明无法获取当前frame,需要调用avcodec_send_packet输入更多的packet。

一般来说,在实际的实现中,EAGAIN是由bsf相关的函数返回的。

  • 调用avcodec_send_packet时,会先调用av_bsf_send_packet,此时如果用于暂存packet的buffer_pkt中含有有效packet时,av_bsf_send_packet会返回EAGAIN,这会导致avcodec_send_packet也返回EAGAIN。

  • 调用avcodec_receive_frame时,如果没有可输出的frame,则会进入decode_receive_frame_internal分支。此时如果用于暂存packet的buffer_pkt中不含有效packet时,ff_bsf_get_packet_ref会返回EAGAIN,这会导致decode_receive_frame_internal返回EAGAIN,从而也使得avcodec_receive_frame也返回EAGAIN。

不过我们注意到avcodec_send_packet中也调用了decode_receive_frame_internal,不过avcodec_send_packet会忽视decode_receive_frame_internal所返回的EAGAIN。

ret = decode_receive_frame_internal(avctx, avci->buffer_frame);

if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)

return ret;

原文:https://www.cnblogs.com/TaigaCon/p/

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

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

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

相关文章

04 中间件-提高框架的可拓展性

到目前为止我们已经完成了 Web 框架的基础部分&#xff0c;使用 net/http 启动了一个 Web 服务&#xff0c;并且定义了自己的 Context&#xff0c;可以控制请求超时。 在前面的controller.go中有一个超时控制逻辑&#xff1a; func FooControllerHandler(c *framework.Context…

【Ap AutoSAR入门与实战开发04】:服务的需求定义以及如何在arxml中定义服务

总目录链接==>> AutoSAR入门和实战系列总目录 文章目录 1 服务的需求定义2 服务的arxml定义2.1 事件中的数据类型定义我们在「【Ap AutoSAR入门与实战开发03】-【Ap_s2s模块02】:到底什么是基于信号,什么是基于服务,两者的主要区别是什么?」的文章中讲到了讲到了服…

如何在ONLYOFFICE v7.3中使用 WRAPROWS、WRAPCOLS公式

在ONLYOFFICE7.3版本更新以来&#xff0c;每次给大家都分享几种函数公式的运用方式&#xff0c;今天在给大家分享两种&#xff0c;分别是&#xff1b;WRAPROWS、WRAPCOLS。 ONLYOFFICE ONLYOFFICE文档是一款免费开源在线办公软件&#xff0c;可以打开阅读并编辑文档、表格和幻…

1247. 交换字符使得字符串相同

1247. 交换字符使得字符串相同 难度中等162收藏分享切换为英文接收动态反馈 有两个长度相同的字符串 s1 和 s2&#xff0c;且它们其中 只含有 字符 "x" 和 "y"&#xff0c;你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时候&am…

轻松入门H3C无线AC上线AP【入门篇】

我们知道华三的最新模拟器支持了无线AC的配置&#xff0c;今天就浅浅的出个无线AC的教程&#xff0c;你上也会的那种。今天我们模拟的是二层环境下&#xff0c;笔者准备了2个AP&#xff0c;以此展示AP上线到AC的教程&#xff0c;并且用手机测试WiFi连接正常&#xff0c;且客户端…

7、nodejs安装

前言&#xff1a;工具下载地址阿里云盘&#xff1a;nodejs&#xff1a;https://www.aliyundrive.com/s/hLAKBgjNUqr提取码: p9q9一、介绍Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于Chrome V8引擎的JavaScript运行环境&#xff0c;使用了一个事件…

【VUE】二 vue指令

目录 一、插值表达式 二、v-bind指令(对标签中的属性进行操作) 三、v-model指令&#xff08;input、select、textarea等。【双向绑定】&#xff09; 四、v-for循环指令 五、v-on(事件指令) 六、v-if条件判断 七、v-show&#xff08;条件显示或隐藏&#xff09; 八、案例…

模型解释性:PFI、PDP、ICE等包的用法

本篇主要介绍几种其他较常用的模型解释性方法。 1. Permutation Feature Importance(PFI) 1.1 算法原理 置换特征重要性(Permutation Feature Importance)的概念很简单&#xff0c;其衡量特征重要性的方法如下&#xff1a;计算特征改变后模型预测误差的增加。如果打乱该特征的…

HCIP-5距离矢量路由协议RIP学习笔记

前言 路由信息协议RIP&#xff08;Routing Information Protocol&#xff09;的简称&#xff0c;它是一种基于距离矢量&#xff08;Distance-Vector&#xff09;算法的协议&#xff0c;使用跳数作为度量来衡量到达目的网络的距离。RIP主要应用于规模较小的网络中。Rip是第一个动…

如何创建“杀手级”SaaS 产品文档?

SaaS 产品的文档至关重要&#xff0c;尽管在 SaaS 初创公司的旋风中&#xff0c;它可能在您的列表中并不重要。它不仅仅是为客户支持节省成本。您可能已经在发布一些文档时做了一些尝试&#xff0c;但现在是时候将您的文档提升到一个新的水平了。由于 SaaS 公司采用订阅模式运营…

【Git】Git使用(保姆级讲解)

1、第一次安装使用 git下载地址&#xff1a;https://git-scm.com/download 1.1 配置用户名、邮箱 ​ 这是非常重要的&#xff0c;因为每次Git提交都会使用该用户信息。 设置 ​ 在 git bash 输入以下命令。 git config --global user.name "" git config --glo…

CV学习笔记-ResNet

ResNet 文章目录ResNet1. ResNet概述1.1 常见卷积神经网络1.2 ResNet提出背景2. ResNet网络结构2.1 Residual net2.2 残差神经单元2.3 Shortcut2.4 ResNet50网络结构3. 代码实现3.1 Identity Block3.2 Conv Block3.3 ResNet网络定义3.4 整体代码测试1. ResNet概述 1.1 常见卷积…

【三维几何学习】MeshCNN: A Network with an Edge

MeshCNN引言一、方法简述1.1 输入1.2 卷积1.3 池化二、实验分析三、改进以及应用引言 MeshCNN是第一个将网格简化引入到池化操作中的网络&#xff1a;合并顶点降低网格分辨率&#xff0c;类似图像中的平均池化。 主页1:https://ranahanocka.github.io/MeshCNN/ 比较详细的讲解…

Java 练习题:输出纯素数

文章目录纯素数简介任务要求思路解析源码奉上运行效果总结纯素数简介 所谓纯素数就是该数本身不仅是素数&#xff0c;并且该数的每一位都是素数。 例如&#xff1a;23,37是纯素数&#xff0c;但13,29不是。 任务要求 输出55555内所有的纯素数&#xff0c;按每行20个的格式化…

JVM 学习(2)—简单理解Java 四大引用(强、软、弱、虚)

一、Java 引用概述 Java 中出现四种引用是为了更加灵活地管理对象的生命周期&#xff0c;以便在不同场景下灵活地处理对象的回收问题。不同类型的引用在垃圾回收时的处理方式不同&#xff0c;可以用来实现不同的垃圾回收策略。Java 目前将其分成四类&#xff0c;类图如下&…

彻底搞懂inner join,left join,right join

1.inner join A inner join B where 条件&#xff0c; 对于A表中的每一行都会去B表的所有行去查找&#xff0c;去匹配&#xff0c;符合条件的就将这两行连接起来 下面用一个例子来帮助实际理解这句话&#xff1a; 创建下面两个表&#xff0c;customers表orders表 输入以下s…

银行软件测试面试题目总结,希望可以帮到你

目录 一、根据题目要求写出具体LINUX操作命令 二、JMETER题目 三、根据题目要求写出具体SQL语句 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&#xff1a;配套学习资料和视频教学 一、根据题目要求写出具体LINUX操作命令 1、分别写出一种…

HTML标签——列表标签 之 自定义列表

HTML标签——列表标签 之 自定义列表 目录HTML标签——列表标签 之 自定义列表一、 场景&#xff1a;在网页的底部导航中通常会使用自定义列表实现。二、标签组成&#xff1a;三、案例实操四、运行效果五、显示特点&#xff1a;六、注意点&#xff1a;七、小结一、 场景&#x…

DeepPath: A Reinforcement Learning Method forKnowledge Graph Reasoning

Innovation使用RL学习KG中的关系路径推理使用Supervised Policy Learning解决&#xff1a;KG中关系图大&#xff0c;如试错训练RL&#xff0c;难以收敛使用双向路径搜索&#xff0c;减少中间节点数量IntroductionPRA是一种学习推理路径的方法&#xff0c;使用基于RandomWalk的重…

智能语音信息处理团队18篇论文被语音技术顶会ICASSP 2023接收

近日&#xff0c;ICASSP 2023会议发出了审稿结果通知&#xff0c;语音及语言信息处理国家工程研究中心智能语音信息处理团队共18篇论文被会议接收&#xff0c;论文方向涵盖语音识别、语音合成、话者识别、语音增强、情感识别、声音事件检测等&#xff0c;各接收论文简介见后文。…