从c++的角度来看ffmpeg 的架构

这篇具有很好参考价值的文章主要介绍了从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,  // 该options 描述的是UDPContext 中的成员.
    .version    = LIBAVUTIL_VERSION_INT,
};

依据udp_class的options 选项中知道它描述的是UDPContext类, 该类在udp.c 中定义
typedef struct UDPContext {
    const AVClass *class;  // 指向 udp_class
    int udp_fd;
    int ttl;
    int udplite_coverage;
    int buffer_size;
    int pkt_size;
    int is_multicast;
    int is_broadcast;
    int local_port;
    int reuse_socket;
    int overrun_nonfatal;
    struct sockaddr_storage dest_addr;
    int dest_addr_len;
    int is_connected;

    /* Circular Buffer variables for use in UDP receive code */
    int circular_buffer_size;
    AVFifoBuffer *fifo;
    int circular_buffer_error;
    int64_t bitrate; /* number of bits to send per second */
    int64_t burst_bits;
    int close_req;
#if HAVE_PTHREAD_CANCEL
    pthread_t circular_buffer_thread;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int thread_started;
#endif
    uint8_t tmp[UDP_MAX_PKT_SIZE+4];
    int remaining_in_dg;
    char *localaddr;
    int timeout;
    struct sockaddr_storage local_addr_storage;
    char *sources;
    char *block;
    IPSourceFilters filters;
} UDPContext;

udp_class 对象被 ff_udp_protocol 对象所引用, 是其私有数据类, .priv_data_class
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 数组) 所引用, 通过枚举URL协议数组可以找到该对象
static const URLProtocol * const url_protocols[] = {
    ...
    &ff_udp_protocol,
    }

url_protocols数组在libavformat/protocols.c 中被定义,以函数接口方式提供对外访问.
例如帮助信息,就是通过查找url_protocols->ff_udp_protocol->udp_class->options 来显示其帮助信息
udp_class 被ff_udp_protocol 所包含,其类是URLProtocol,
这些概念都在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 对象表
其它的一堆对象也是如此组织的.文章来源地址https://www.toymoban.com/news/detail-626121.html

到了这里,关于从c++的角度来看ffmpeg 的架构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 基础知识 五 ( 来看来看 面向对象的继承 上篇 )

    C++ 继承是指派生类(子类)从基类(父类)继承属性和行为的过程。我们可以创建一个新的类,该类可以继承另一个类的数据属性和方法。 在上述代码中,我们定义了一个父类 Person 与一个子类 Student。Student 类继承了 Person 类的属性和方法,包括 name、age、gender 和 eat() 函数

    2024年02月03日
    浏览(96)
  • CAP 角度下的 Redis 与 Zookeeper 锁架构比较

    在分布式系统设计中,CAP理论提供了一个重要的框架,帮助我们理解在一致性、可用性和分区容忍性之间的权衡。在这篇博客中,我们将从CAP的角度出发,比较Redis与Zookeeper在锁架构上的异同。 一致性(Consistency): Redis强调数据的强一致性。在分布式锁的场景中,当一个节

    2024年01月22日
    浏览(32)
  • 多角度解读新兴公链Sui:团队、架构、代币、生态等

    随着上周Solana和Nomad黑客事件的发生,对安全、可扩展的区块链需求越来越显著。我们之前的报道曾讨论过Aptos,它是一个由Meta(前Facebook)员工创建的基于Move编程语言的区块链。Aptos并不是唯一的区块链新宠。在本文中,我们将讨论由Mysten Labs开发的一个区块链项目Sui,其目

    2024年02月01日
    浏览(62)
  • 从架构角度看网络安全:数字化时代企业如何构建防御体系?

    导语 | 数字化时代,网络安全已经成为企业发展的重中之重,通过体系化的安全建设,企业可以从容应对愈加复杂的网络安全挑战。今天,我们特邀了腾讯云 TVP、赛博英杰科技董事长 谭晓生老师,他将从资深技术专家视角解读如何以架构思维来规划企业网络安全建设,为当

    2024年02月11日
    浏览(137)
  • 图解人工智能知识架构(从系统角度告诉你人工智能到底学些啥)

    很多人都想学习人工智能,但是却不知道该学些啥?从宏观的视角搞清楚人工智能到底需要学习哪些领域的知识是至关重要的。这就好比要去逛一座大的商场,非常需要一份商场的楼层导览图,它能够告诉你各个楼层商户的分布;又好比去一个风景区游玩,非常需要一份景区

    2024年02月04日
    浏览(47)
  • 你知道什么是C++的信号处理嘛?不妨来看看这篇

    名字:阿玥的小东东 学习:python、C/C++ 博客主页: 阿玥的小东东的博客_CSDN博客-pythonc++高级知识,过年必备,C/C++知识讲解领域博主 目录 signal() 函数 raise() 函数 函数声明

    2024年02月08日
    浏览(45)
  • 【C++】:想知道如何实现互译字典吗?来看二叉搜索树

    二叉搜索树好文! 文章目录 前言 一、实现搜索二叉树 二、二叉搜索树的应用 1.K模型 2.KV模型 总结 二叉搜索树概念 : 二叉搜索树又称二叉排序树,它或者是一棵空树 ,或者是具有以下性质的二叉树 : 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的

    2024年02月01日
    浏览(33)
  • 从编译角度看c和c++混合编译

    往期地址: 操作系统系列一 —— 操作系统概述 操作系统系列二 —— 进程 操作系统系列三 —— 编译与链接关系 操作系统系列四 —— 栈与函数调用关系 操作系统系列五——目标文件详解 操作系统系列六 —— 详细解释【静态链接】 本期主题: c和c++混合编译 参考前面文

    2023年04月09日
    浏览(22)
  • 从汇编代码的角度去理解C++多线程编程问题

    目录 1、多线程问题实例 2、理解该多线程问题的预备知识 2.1、二进制机器码和汇编代码

    2024年02月06日
    浏览(36)
  • [ORB/BEBLID] 利用OpenCV(C++)实现尺度不变性与角度不变性的特征找图算法

    本文只发布于利用OpenCV实现尺度不变性与角度不变性的特征找图算法和知乎 一般来说,利用OpenCV实现找图功能,用的比较多的是模板匹配(matchTemplate)。笔者比较喜欢里面的NCC算法。但是模板有个很明显的短板,面对尺度改变,角度改变的目标就无能为力了。因此本文旨在

    2024年02月05日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包