从c++的角度来看ffmpeg 的架构
-------------------------------------------------------------------------
author: hjjdebug
date: 2023年 08月 01日 星期二 11:26:40 CST
descriptor: 从c++的角度来看ffmpeg 的架构
-------------------------------------------------------------------------
1. AVClass 类就是一个普通的类. 基本的类.
AVClass 包含了一个AVOption *option, 这个指针会指向一个AVOption 数组.
-------------------------------------------------------------------------
-------------------------------------------------------------------------
2. ffmpeg 中包含了很多context类, 它们共同继承于baseContext类.
-------------------------------------------------------------------------
这个BaseContext类就是:
class BaseContext{
AVClass *class;
}
比方说AVCodecContext类, 它实际上是 class AVCodecContext::public BaseContext
只是ffmpeg 用c 写成,它并没有显示声明baseContext类, 而是在隐式的使用了.
即它在AVCodecContext 中的第一项 声明为 AVClass *class,
例如: AVCodecContext 类是这样声明的.
typedef struct AVCodecContext {
const AVClass *av_class;
int log_level_offset;
....
};
所谓子类,就是继承了父类的属性和方法.
一个父类领导了一群子类, 这有什么好处呢? 好处有2,
1.所有的子类都像父类,子类指针可以退化为父类指针(子类退化机制)
2.在还没有确认子类到底是什么的时候,父类代码就可以书写了. (父类不依赖于子类)
AVClass 是在libavutil/log.h 中定义的,
由它可以创作出很多实例.查ffmpeg 源代码,有431个对象,其中有的类.class_name=""
举例: 定义了一个udp_class
static const AVClass udp_class = {
.class_name = "udp",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
依据udp_class的options 选项中知道它描述的是UDPContext类, 该类在url.h 中定义
typedef struct URLContext {
const AVClass *av_class; // 它的第一个成员是AVClass, 所以继承自baseAVClass 类
const struct URLProtocol *prot; //包含了一个协议指针,会指向一个具体的协议,这为以后的委托,转发等提供了方便(想起了c++的委托模式或代理模式)
void *priv_data; // 找到了协议,会为协议对象分配内存,这是协议对象地址.
//其它意义比较明确
char *filename; //url 名称
int flags; //标志
int max_packet_size; //最大包大小
int min_packet_size; //最小包大小
int is_streamed; //是否是流(流是不能seek的)
int is_connected; //是否已连接
AVIOInterruptCB interrupt_callback; //数据中断时call_back函数
int64_t rw_timeout; //读写最长等待时间,ms
const char *protocol_whitelist; //白名单
const char *protocol_blacklist; //黑名单
} URLContext;
udp_class 被 ff_udp_protocol 对象所引用
const URLProtocol ff_udp_protocol = {
.name = "udp",
.url_open = udp_open,
.url_read = udp_read,
.url_write = udp_write,
.url_close = udp_close,
.url_get_file_handle = udp_get_file_handle,
.priv_data_size = sizeof(UDPContext), //URLProtocol 中定义这个私有类的大小,此处是UDPContext类
.priv_data_class = &udp_class, //URLProtocol 协议中确实有一项叫priv_data_class,此处是udp_class
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
ff_udp_protocol被url_protocols(URLProtocol 数组) 所引用
static const URLProtocol * const url_protocols[] = {
...
&ff_udp_protocol,
}
url_protocols数组在libavformat/protocols.c 中被使用,以函数接口方式提供对外访问.
例如帮助信息,就是通过查找url_protocols->ff_udp_protocol->udp_class->options 来显示其帮助信息
udp_class 的父类是URLProtocal, 其对象是谁? 要扒吗? 其父对象是URLContext, 其类是ffurl_context_class(在avio.c中定义)
这些都在url.h中定义的(最关键的是URLProtocal, URLContext),顺便再看看其它函数... 在avio.c 中实现
avio.c 中的代码都很简短但有技巧,所谓技巧就是委托,转发.
我目前的理解通常把保留一个对象的指针,当调用一个函数时,去调用这个对象的对应函数叫委托或转发.
而把调用一个函数时,同时传来一个对象指针,我们回调这个对象函数叫策略模式
再举一个AVInputFormat 的例子:
mpegts 是一种输入格式. 它的帮助信息是如何显示的? 如何了解它,掌握它? (从这一点入手,找到与它关联的知识)
我们查 :
$ffmpeg -formats // 显示了所有formats, 其中mpegts 即属于Demuxer 也属于 muxer
$ffmpeg -demuxer // 显示了所有demuxer, 其中MPEG-TS (MPEG-2 Transport Stream)
$ffmpeg -h demuxer=mpegts // 向我们显示了该demuxer 的所有选项
mpegts demuxer AVOptions:
-resync_size <int> .D......... set size limit for looking up a new synchronization (from 0 to INT_MAX) (default 65536)
-fix_teletext_pts <boolean> .D......... try to fix pts values of dvb teletext streams (default true)
-ts_packetsize <int> .D....XR... output option carrying the raw packet size (from 0 to 0) (default 0)
-scan_all_pmts <boolean> .D......... scan and combine all PMTs (default auto)
-skip_unknown_pmt <boolean> .D......... skip PMTs for programs not advertised in the PAT (default false)
-merge_pmt_versions <boolean> .D......... re-use streams when PMT's version/pids change (default false)
从该help 入手, 我们找一下这个demuxer 对象,它是以怎样的数据流来工作的?
static void show_help_demuxer(const char *name)
{
const AVInputFormat *fmt = av_find_input_format(name); // 对象AVInputFormat, 包含私有类指针 fmt->priv_class
if (fmt->priv_class)
show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM,100); //,显示该私有类的帮助信息,此忽略(请参考<ffmpeg 帮助系统>博客)
}
由context类构建对象就不举例了,读代码时仔细体会就可以了.
-------------------------------------------------------------------------
3. ffmpeg 中的对象: 这些对象都是常对象,存在于全局变量中
-------------------------------------------------------------------------
从configure 文件中找到了以下基础列表, 它们还可以组合成其它列表组合. 这里就是ffmpeg的基础对象了.
FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c)
OUTDEV_LIST=$(find_things_extern muxer AVOutputFormat libavdevice/alldevices.c outdev)
INDEV_LIST=$(find_things_extern demuxer AVInputFormat libavdevice/alldevices.c indev)
MUXER_LIST=$(find_things_extern muxer AVOutputFormat libavformat/allformats.c)
DEMUXER_LIST=$(find_things_extern demuxer AVInputFormat libavformat/allformats.c)
ENCODER_LIST=$(find_things_extern encoder AVCodec libavcodec/allcodecs.c)
DECODER_LIST=$(find_things_extern decoder AVCodec libavcodec/allcodecs.c)
PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parsers.c)
BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c)
HWACCEL_LIST=$(find_things_extern hwaccel AVHWAccel libavcodec/hwaccels.h)
PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c)
以AVCodec 对象列表为例来说明:
后面每一个地址都是一个AVCodec对象 的地址
static const AVCodec * const codec_list[] = {
&ff_a64multi_encoder,
&ff_a64multi5_encoder,
&ff_alias_pix_encoder,
&ff_amv_encoder,
...
&ff_h264_decoder,
.....
}
以ff_h264_decoder 为例:
ff_h264_decoder 就是一个AVCodec 对象, 由于它是AVCodec 的一个实例,所以对AVCodec 所要求的指针函数都要实现.
属性也都要赋值(或给默认值)
AVCodec ff_h264_decoder = {
.name = "h264",
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.priv_data_size = sizeof(H264Context),
.init = h264_decode_init,
.close = h264_decode_end,
.decode = h264_decode_frame,
.capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 |
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS |
AV_CODEC_CAP_FRAME_THREADS,
.hw_configs = (const AVCodecHWConfigInternal *const []) {
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING |
FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP,
.flush = h264_decode_flush,
.update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),
.profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles),
.priv_class = &h264_class,
};
这里AVCodec 在libavcodec/codec.h中声明
它只是一个接口,没有具体的实现,每一个实例都要实现它的接口.
该头文件还声明了几个函数,例如 avcodec_find_decoder,avcodec_find_encoder,avcodec_iterate等
这就在一个简单的文件 allcodecs.c 中来实现了
核心是av_codec_iterate(), 就是查找一个AVCodec 对象表
其它的一堆对象也是如此组织的.
相关文章:
从c++的角度来看ffmpeg 的架构
------------------------------------------------------------------------- author: hjjdebug date: 2023年 08月 01日 星期二 11:26:40 CST descriptor: 从c的角度来看ffmpeg 的架构 ------------------------------------------------------------------------…...
Ubuntu安装JDK与IntelliJ IDEA
目录 前言 Ubuntu 安装 JDK 1、更新软件包列表 2、安装OpenJDK 3、验证安装 Ubuntu安装IntelliJ IDEA 1、下载 IntelliJ IDEA 2、解压缩 IntelliJ IDEA 安装包 3、移动 IntelliJ IDEA 到安装目录 4、启动 IntelliJ IDEA 前言 APT(Advanced Package Tool&…...
【雕爷学编程】Arduino动手做(182)---DRV8833双路电机驱动模块2
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…...
一个完整的http请求响应过程
一、 HTTP请求和响应步骤 以上完整表示了HTTP请求和响应的7个步骤,下面从TCP/IP协议模型的角度来理解HTTP请求和响应如何传递的。 二、TCP/IP协议 TCP/IP协议模型(Transmission Control Protocol/Internet Protocol),包含了一系…...
Unity通过代码切换材质
效果展示 代码 using System.Collections; using System.Collections.Generic; using UnityEngine;public class MaterialSwitcher : MonoBehaviour {public Material newMaterial; // 新材质private Material oldMaterial; // 旧材质private Renderer renderer; // 渲染器组件…...
Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐
目录 前言 一、根据坐标经纬度计算两点距离(5种方法) 1.方法一 2.方法二 3.方法三 4.方法四 5.方法五 5.1 POM引入第三方依赖 5.2 代码 6.测试结果对比 二、校验经纬度是否在制定区域内 1.判断一个坐标是否在圆形区域内 2.判断一个坐标是否…...
PIC单片机如何设计延时
PIC单片机如何设计延时 PIC单片机的延时基本有两种,一种是自己设计的delay()函数,另一种就是利用其自带的Time定时器。当然一般Time定时器的精度要高于自己设计delay()函数,Time定时器是单片机内部的硬件寄存器模块,而delay()函数是利用自加自减来实现延时,代码进行顺序执…...
FFmpeg常见命令行(二):FFmpeg转封装
前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个, 对应的要学习的内容是:如何使…...
全面升级:华为鸿蒙HarmonyOS4正式发布,玩趣个性化,小艺AI升级
8月4日新闻,今天下午,华为正式发布了最新版本的鸿蒙操作系统——HarmonyOS 4! 在华为发布会上,鸿蒙HarmonyOS迎来了一系列令人激动的功能升级。其中包括个性化空间、多种生产力工具以及增强的手机AI助手"小艺"。这次更…...
【python】使用Selenium和Chrome WebDriver来获取 【腾讯云 Cloud Studio 实战训练营】中的文章信息
文章目录 前言导入依赖库设置ChromeDriver的路径创建Chrome WebDriver对象打开网页找到结果元素创建一个空列表用于存储数据遍历结果元素并提取数据提取标题、作者、发布时间等信息判断是否为目标文章提取目标文章的描述、阅读数量、点赞数量、评论数量等信息将提取的数据存储为…...
使用Feign 的远程调用,把mysql数据导入es
要把数据库数据导入到elasticsearch中,包括下面几步: 1)将商品微服务中的分页查询商品接口定义为一个FeignClient,放到feign-api模块中 2)搜索服务编写一个测试业务,实现下面功能: 调用item-ser…...
Java课题笔记~ MyBatis接口开发(代理开发)
使用XML文件进行开发,在调用SqlSession进行操作时,需要指定MyBatis映射文件中的方法,这种调用方式过于烦琐。为解决此问题,MyBatis提供了接口开发的方式。 接口开发的目的: 解决原生方式中的硬编码 简化后期执行SQL …...
从数学到深度学习的学习资料及教程合集
诸神缄默不语-个人CSDN博文目录 目前仅收集免费内容,最多需要买本纸质书。 付费的如果有免费版本我也会收录。 链接如失效请联系我。 这个笔记主要是为我自己准备的,算是一个可公开的to do list(其实做不完的我也知道)ÿ…...
nn.CrossEntropyLoss()报错
RuntimeError: “nll_loss_forward_reduce_cuda_kernel_2d_index” not implemented for ‘Float’ Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/zz/anaconda3/envs/torch1.11/lib/python3.7/site-pack…...
【BASH】回顾与知识点梳理(一)
【BASH】回顾与知识点梳理 一 前言一. 认识与学习 BASH1.1 硬件、核心与 Shell1.2 为何要学文字接口的 shell?1.3 系统的合法 shell 与 /etc/shells 功能1.4 Bash shell 的功能1.5 查询指令是否为 Bash shell 的内建命令: type1.6 指令的下达与快速编辑按…...
AWS Amplify 部署node版本18报错修复
Amplify env:Amazon Linux:2 Build Error : Specified Node 18 but GLIBC_2.27 or GLIBC_2.28 not found on build 一、原因 报错原因是因为默认情况下,AWS Amplify 使用 Amazon Linux:2 作为其构建镜像,并自带 GLIBC 2.26。不过,…...
K8S添加yum源并安装kubectl/kubeadm/kubelet组件
1.安装kubectl/kubeadm/kubelet ##添加yum 源 cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled1 gpgcheck0 repo_gpgcheck0 gpgkeyhttps://mirr…...
kafka生产者指定ip
kafka生产者指定ip 最近工作中遇到一个问题,记录一下,需求中要求往kafka上推送信息。本来是个很简单的需求,但是踩了一个坑。 我通过spring boot集成了kafka写了一个生产者,客户那边给我三个节点的ip,然后我也没多想…...
python 封装sql 增删改查连接MySQL
select * from Teacher limit 10 连接字符串配置MysqlConfig.py class MysqlConfig:HOST 192.168.56.210PORT 3306USER rootPASSWORD 1qaz0987654321DBStudentDBCHARSET utf8封装增删改查MysqlConnection.py Author: tkhywang 2810248865qq.com Date: 2023-06-19 15:44:48 Las…...
Flink正常消费一段时间后,大量反压,看着像卡住了,但又没有报错。
文章目录 前言一、原因分析二、解决方案 前言 前面我也有提到,发现flink运行一段时间后,不再继续消费的问题。这个问题困扰了我非常久,一开始也很迷茫。又因为比较忙,所以一直没有时间能够去寻找答案,只是通过每天重启…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...
【Java】Ajax 技术详解
文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...
break 语句和 continue 语句
break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...
初级程序员入门指南
初级程序员入门指南 在数字化浪潮中,编程已然成为极具价值的技能。对于渴望踏入程序员行列的新手而言,明晰入门路径与必备知识是开启征程的关键。本文将为初级程序员提供全面的入门指引。 一、明确学习方向 (一)编程语言抉择 编…...
SQLSERVER-DB操作记录
在SQL Server中,将查询结果放入一张新表可以通过几种方法实现。 方法1:使用SELECT INTO语句 SELECT INTO 语句可以直接将查询结果作为一个新表创建出来。这个新表的结构(包括列名和数据类型)将与查询结果匹配。 SELECT * INTO 新…...
Neo4j 完全指南:从入门到精通
第1章:Neo4j简介与图数据库基础 1.1 图数据库概述 传统关系型数据库与图数据库的对比图数据库的核心优势图数据库的应用场景 1.2 Neo4j的发展历史 Neo4j的起源与演进Neo4j的版本迭代Neo4j在图数据库领域的地位 1.3 图数据库的基本概念 节点(Node)与关系(Relat…...
