从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 对象表
其它的一堆对象也是如此组织的.

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

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

相关文章

maxwell 基于zookeeper的高可用方案

Maxwell版本1.39.2 一&#xff1a; 添加zk的pox文件 <!-- customize HA --> <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>5.4.0</version> </dependency>&…

查看gz文件 linux zcat file.gz mtx.gz

可以使用以下命令来查看 gz 压缩文件的内容&#xff1a; zcat file.gz 1 该命令会将 file.gz 文件解压并输出到标准输出&#xff0c;可以通过管道符将其与 grep 命令结合使用来查找需要的关键词&#xff0c;例如&#xff1a; zcat file.gz | grep keyword 1 该命令会将 file.gz…

Electron 开发,报handshake failed; returned -1, SSL error code 1,错误

代码说明 在preload.js代码中&#xff0c;暴露参数给渲染线程renderer.js访问&#xff0c; renderer.js 报&#xff1a;ERROR:ssl_client_socket_impl.cc(978)] failed; returned -1, SSL error code 1,错误 问题原因 如题所说&#xff0c;跨进程传递消息&#xff0c;这意味…

Rust 开发环境搭建【一】

Rust 开发环境 推荐 搭建&#xff1a; 安装 rust 语言 以及 工具链 推荐安装方法&#xff1a;rustup curl --proto ‘https’ --tlsv1.2 -sSf https://sh.rustup.rs | sh 在国内如果访问速度慢&#xff0c;可以使用清华大学提供的镜像服务&#xff1a; https://mirrors.tu…

Python中实现多个列表、字典、元组、集合的连接

目录 目录 前言 一、列表 1、运算符 2、extend&#xff08;&#xff09;方法 3、解包操作 * 二、字典 1、update&#xff08;&#xff09;方法 2、解包操作 ** 三、元组 1、 运算符 2、解包操作 * 四、集合 1、union方法 2、| 运算符 3、解包操作 * 五、不同类…

Python 多线程

Python 多线程 多线程类似于同时执行多个不同程序&#xff0c;多线程运行有如下优点&#xff1a; 使用线程可以把占据长时间的程序中的任务放到后台去处理。用户界面可以更加吸引人&#xff0c;这样比如用户点击了一个按钮去触发某些事件的处理&#xff0c;可以弹出一个进度条…

学习单片机的秘诀:实践与坚持

在学习单片机时&#xff0c;将实践与学习结合起来是一个很好的方法。不要一上来就死磕指令和名词&#xff0c;而是边学边做实验&#xff0c;循序渐进地理解和应用指令。通过实验&#xff0c;你能亲身感受到指令的控制效果&#xff0c;增强对单片机的理解和兴趣。 学习单片机不…

Android Ble蓝牙App(二)连接与发现服务

Ble蓝牙App&#xff08;二&#xff09;连接与发现服务 前言正文一、GATT回调二、连接和断连三、连接状态回调四、发现服务五、服务适配器六、显示服务七、源码 前言 在上一篇中我们进行扫描设备的处理&#xff0c;本文中进行连接和发现服务的数据处理&#xff0c;运行效果图如下…

Electron 工具进程utilityProcess 使用中遇到的坑点汇集

简介 这是基于 node.js 中的子进程的概念推出来的&#xff0c;可参考链接&#xff1a;utilityProcess | Electron 官网有一句话非常重要&#xff0c;它提供一个相当于 Node.js 的 child_process.fork API&#xff0c;但使用 Chromium 的 Services API 代替来执行子进程。这句话…

AI量化模型预测——baseline学习笔记

一、赛题理解 1. 赛题名称 AI量化模型预测 2. 赛题理解 本赛事是一个量化金融挑战&#xff0c;旨在通过大数据与机器学习的方法&#xff0c;使用给定的训练集和测试集数据&#xff0c;预测未来中间价的移动方向。参赛者需要理解市场行为的原理&#xff0c;创建量化策略&#…

element表格+表单+表单验证结合u

一、结果展示 1、图片 2、描述 table中放form表单&#xff0c;放输入框或下拉框或多选框等&#xff1b; 点击添加按钮&#xff0c;首先验证表单&#xff0c;如果存在没填的就验证提醒&#xff0c;都填了就向下添加一行表单表格&#xff1b; 点击当前行删除按钮&#xff0c;…

剑指Offer05.替换空格

剑指Offer05.替换空格 目录 剑指Offer05.替换空格题目描述解法一&#xff1a;遍历添加解法二&#xff1a;原地修改 题目描述 请实现一个函数&#xff0c;把字符串s中的每个空格都替换成“%20”。 解法一&#xff1a;遍历添加 由于每次替换都要把一个空格字符变成三个字符&a…

Godot 4 源码分析 - 碰撞

碰撞功能应该是一个核心功能&#xff0c;它能自动产生相应的数据&#xff0c;比如目标对象进入、离开本对象的检测区域。 基于属性设置&#xff0c;能碰撞的都具备这样的属性&#xff1a;Layer、Mask. 在Godot 4中&#xff0c;Collision属性中的Layer和Mask属性是用于定义碰撞…

Unity 编辑器选择器工具类Selection 常用函数和用法

Unity 编辑器选择器工具类Selection 常用函数和用法 点击封面跳转下载页面 简介 在Unity中&#xff0c;Selection类是一个非常有用的工具类&#xff0c;它提供了许多函数和属性&#xff0c;用于操作和管理编辑器中的选择对象。本文将介绍Selection类的常用函数和用法&#xff…

Redis-Java客户端-Jedis

目录 01.导入依赖 02.进行测试连接 03.使用JedisPool 04.修改测试的代码 01.导入依赖 新建一个mevan工程&#xff0c;在pom文件下导入相应的依赖&#xff0c;相依的依赖可以去官网查找 spring官网&#xff1a;Spring Data Redis <dependencies><!-- jedis -->…

伊语IM即时通讯源码/im商城系统/纯源码IM通讯系统安卓+IOS前端纯原生源码

伊语IM即时通讯源码/im商城系统/纯源码IM通讯系统安卓IOS前端纯原生源码&#xff0c; 后端是java源码。

2.4 网络安全新技术

数据参考&#xff1a;CISP官方 目录 云计算安全大数据安全移动互联网安全物联网安全工业互联网安全 一、云计算安全 1、云计算定义 云计算是指通过网络访问可扩展的、灵活的物理或虚拟共享资源池&#xff0c;并按需自助获取和管理资源的模式。在云计算中&#xff0c;计算资…

深度学习之双线性插值

1、单线性插值 单线性插值是一种用于估计两个已知数据点之间未知点的方法。它基于线性关系&#xff0c;通过计算目标位置的值&#xff0c;使用已知点之间的线性函数进行插值。这在图像处理中常用于放缩、旋转等操作&#xff0c;计算简单&#xff0c;产生平滑结果&#xff0c;但…

小白也能懂!业务中台与数据中台究竟是什么?

大家好&#xff0c;今天我们要讨论的是业务中台与数据中台&#xff0c;或许你对这些名词还不太熟悉&#xff0c;但别担心&#xff0c;接下来我将为你详细解释这两个概念&#xff0c;并且用通俗易懂的语言来解释它们。 业务中台是什么&#xff1f; 首先&#xff0c;让我们来了解…

ubuntu搭建wifi热点,共享网络(x86、arm相同)

目录 1 首先检查网络管理器服务是否开启 &#xff08;ubuntu需要界面&#xff09; 2 创建并配置需要共享的wifi 首先&#xff0c;明确下这篇文章说的是啥&#xff0c;是为了在ubuntu系统的电脑上&#xff0c;搭建一个wifi热点&#xff0c;供其他移动设备连接上网。就像你…