通过前面三篇文章的分析大致了解了ffmpeg中demuxer/decoder模块的内部大致结构和数据处理流程。在阅读源码的过程中经常会看到XXXContext,AVClass xxx_class, AVOption XXX_options。本篇文章将来分析下它们三者之间的联系以及它们的作用。

Context,AVClass, AVOption三者之间关系

在搞清楚三者的关系之前,先想想它们是什么。以下是个人的理解。
Context: 用来描述一个功能模块的属性的对象。一般有多态性质的Context中第一个成员就是AVClass。
**AVClass:**是Context与AVOption的一个纽带。通过Context的AVClass成员找到AVOption,用于动态设置参数选项。
AVOption: ffmpeg中设置动态参数的一种方式。有很好用的接口来set/get具体的参数值。
通过上面的描述它们三者之间的关系可以简单描述下:
Context是用于描述一个模块,里面定义该模块的一些参数,变量,子模块,成员函数等。AVClass只存在于Context中,作为Context的一个成员。而AVOption一般只存在于AVClass中,用于定义模块的动态参数。即通过Context找到AVClass, 通过AVClass找到AVOption。其目的是定义一套标准接口设置各个模块的动态参数。

上面的描述可能有些抽象,下面举一个实际的例子。

  • AVFormatContext 定义与分配
    可以看到AVFormatContext中第一个成员就是AVClass
struct AVFormatContext {const AVClass *av_class;const struct AVInputFormat *iformat;void *priv_data;.........其他成员变量.......;
}AVFormatContext *avformat_alloc_context(void)
{FFFormatContext *const si = av_mallocz(sizeof(*si));AVFormatContext *s;s = &si->pub;s->av_class = &av_format_context_class; //赋值s->io_open  = io_open_default;s->io_close = ff_format_io_close_default;s->io_close2= io_close2_default;av_opt_set_defaults(s);..............................;return s;
}
  • AVClass定义与实现
    可以看到AVClass中成员option即为AVOption
static const AVClass av_format_context_class = {.class_name     = "AVFormatContext",.item_name      = format_to_name,.option         = avformat_options,.version        = LIBAVUTIL_VERSION_INT,.child_next     = format_child_next,.child_class_iterate = format_child_class_iterate,.category       = AV_CLASS_CATEGORY_MUXER,.get_category   = get_category,
};

AVOption的定义与实现
可以看到avformat_options中定义了多个动态参数,这些option可通过ap_opt_xxx 系列函数才访问/修改这些option。

typedef struct AVOption {const char *name;const char *help;int offset;enum AVOptionType type;union {int64_t i64;double dbl;const char *str;/* TODO those are unused now */AVRational q;} default_val;double min;                 ///< minimum valid value for the optiondouble max;                 ///< maximum valid value for the optionint flags;const char *unit;
} AVOption;static const AVOption avformat_options[] = {{"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"},
{"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT64, {.i64 = 5000000 }, 32, INT64_MAX, D},
..................,
}

使用Context实现多态

还是以AVFormatContext 为例子,详细说明下。众所周知,AVFormatContext负责描述demux/mux功能模块。但音视频的container很多,有MP4, AV1,ts等,不同的格式数据内容差异很大,demux过程逻辑完全不同,但使用FFMPEG进行demux时,使用这只会看见AVFormatContext而无需关心数据格式是什么。那么AVFormatContext是怎么做到的呢 ?这是不是与C++中的多态很像。AVFormatContext是一个父类,各个具体格式的数据demux时是调用子类的实现。

例子AVInputFormat

我们再来回顾下AVFormatContext 的定义:

struct AVFormatContext {const AVClass *av_class;const struct AVInputFormat *iformat; //demuxer, AVInputFormat如果命名为AVInputFormatContext更合适const struct AVOutputFormat *oformat; //muxer, AVOutputFormat 如果命名为AVOutputFormatContext更合适void *priv_data;.........其他成员变量.......;
}

AVFormatContext 中的AVClass *av_class定义了demux/mux模块公有的option,参数和功能接口。
再来看下AVInputFormat的定义:

typedef struct AVInputFormat {const AVClass *priv_class; ///< AVClass for the private contextint priv_data_size;const char *name;const char *long_name;int flags;const char *extensions;const struct AVCodecTag * const *codec_tag;const char *mime_type;int raw_codec_id;int flags_internal;int (*read_probe)(const AVProbeData *);int (*read_header)(struct AVFormatContext *);int (*read_close)(struct AVFormatContext *);int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,int64_t *pos, int64_t pos_limit);int (*read_play)(struct AVFormatContext *);int (*read_pause)(struct AVFormatContext *);int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
} AVInputFormat;

通过AVInputFormat的定义可以看到定义了demuxer模块公有的成员变量和成员函数。重点看下priv_class和priv_data_size的作用。

typedef struct AVInputFormat {const AVClass *priv_class; //某个具体container demuxer的context中的classint priv_data_size; //某个具体container demuxer的context中的size.................;
}struct AVFormatContext {const AVClass *av_class;const struct AVInputFormat *iformat; //demuxerconst struct AVOutputFormat *oformat; //muxervoid *priv_data //某个具体container demuxer/muxer的context的指针,子类需要的参数变量.........其他成员变量.......;
}

如果当前需要处理的是ts格式的数据,那么这些变量具体的含义如下:

typedef struct AVInputFormat {const AVClass *priv_class = &mpegts_class; //静态变量mpegts_class的地址int priv_data_size = sizeof(MpegTSContext); //MpegTSContext结构体的大小.................;
}struct AVFormatContext {const AVClass *av_class;const struct AVInputFormat *iformat; //demuxerconst struct AVOutputFormat *oformat; //muxervoid *priv_data = av_malloc(sizeof(MpegTSContext)); //分配一个MpegTSContext.........其他成员变量.......;
}

上面的这些具体是如何实现的?上代码:
在ffmpeg\libavformat\demux.c文件中的avformat_open_input(…)函数有如下一段代码,

   //AVFormatContext *sif (s->iformat->priv_data_size > 0) {if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {ret = AVERROR(ENOMEM);goto fail;}if (s->iformat->priv_class) {*(const AVClass **) s->priv_data = s->iformat->priv_class;av_opt_set_defaults(s->priv_data);if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)goto fail;}}

此时假如iformat为AVInputFormat ff_mpegts_demuxer,那么s->iformat->priv_data_size和s->iformat->priv_class是什么呢 ?
priv_data_size值就是sizeof(MpegTSContext), priv_class的值是静态变量mpegts_class的地址。

const AVInputFormat ff_mpegts_demuxer = {.name           = "mpegts",.long_name      = NULL_IF_CONFIG_SMALL("MPEG-TS (MPEG-2 Transport Stream)"),.priv_data_size = sizeof(MpegTSContext),.read_probe     = mpegts_probe,.read_header    = mpegts_read_header,.read_packet    = mpegts_read_packet,.read_close     = mpegts_read_close,.read_timestamp = mpegts_get_dts,.flags          = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,.priv_class     = &mpegts_class,
};

例子AVInputFormat用c++实现

如果将AVInputFormat用c++来实现,就是这样:

class AVInputFormat {public:const char *name;const char *long_name;int flags;const char *extensions;const struct AVCodecTag * const *codec_tag;const char *mime_type;int raw_codec_id;int flags_internal;virtual int (*read_probe)(......) = 0;virtual  int (*read_header)(......) = 0;virtual int (*read_close)(......) = 0 ;...............;
};class AVInputFormatMpegTS:public AVInputFormat {public:struct MpegTSContext ctx;int (*read_probe)(......) override;int (*read_header)(......) override;int (*read_close)(......) override ;...............;
};

【FFMPEG源码分析】ffmpeg中context与AVClass,AVOption之间的关系相关推荐

  1. FFMPEG源码分析(一)

    FFMPEG源码分析(一) ffmpeg之前公司项目中就使用过,但是多停留于应用层面,实现某个功能时,需要哪些结构体以及调用哪些函数.最近想系统的学习一下ffmpeg,于是开始看雷霄骅https:// ...

  2. FFMPEG源码分析(二)

    ffmpeg源码分析之数据流 本文主要介绍ffmpeg的数据流,在ffmpeg中主要分有三个主要用途用于媒体流的解码播放,媒体流的转换(解码之后再编码)和媒体流录制. 媒体流的解码播放 在ffmpeg ...

  3. FFMPEG 源码分析

    FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库.FFMPEG是在linux下开发的,但也有windows下的编译版本. ffmpeg项目由以下几部分组 ...

  4. ffmpeg源码分析-parse_optgroup

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

  5. ffmpeg源码分析-ffmpeg_parse_options

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

  6. ffmpeg源码分析-transcode_step

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

  7. FFmpeg源码分析-直播延迟-内存泄漏

    FFmpeg源码分析-直播延迟-内存泄漏|FFmpeg源码分析方法|ffmpeg播放为什么容易产生延迟|解复用.解码内存泄漏分析 专注后台服务器开发,包括C/C++,Linux,Nginx,ZeroM ...

  8. ffmpeg源码分析与应用示例(一)——H.264解码与QP提取

    本文包含以下内容 1.H.264解码流程详述与对应ffmpeg源码解析 2.针对一个应用实例介绍通过修改ffmpeg源码解决问题的方案 具有较强的综合性. 先介绍一下在第二部分中将要解决的实际问题:自 ...

  9. Android源码分析-全面理解Context

    前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...

最新文章

  1. 堆排序算法的java实现_堆排序算法的JAVA实现
  2. 今日头条 文章采集_我在今日头条的成长之路—文章的排版与结构
  3. 别看360完成私有化 仍有三因素阻碍中概股回归
  4. linux下各种小命令
  5. 随手小记 才知道[阁楼藏尸|未来闪影]
  6. 机器学习实战(一)k-近邻kNN(k-Nearest Neighbor)
  7. itextpdf添加表格元素_基操勿6第四期:PPT表格美化
  8. java将jfif格式转换成ipg_无需工具直接将jfif格式图片批量修改为jpg格式图片的方法...
  9. MATLAB Cholesky分解
  10. Linux系统下LightDM详解
  11. 微信 dat 文件还原
  12. node生成唯一设备id(node-machine-id)
  13. 中考可以使用计算机吗,2017年中考可以带计算器吗
  14. 【C语言/入门游戏】猜数字,关机指令游戏及go to语句
  15. “双碳”背景下,消费金融如何抓住“绿色”机遇?
  16. Dell precision 7720 移动工作站 nvidia 显卡安装说明
  17. 游戏skr而止,漏洞周而复始 —— 游戏合约漏洞全面汇总 | 漏洞分析连载之六
  18. 日报2015/11/11(第一行代码读书笔记)
  19. 数字化和社会化商业转型中首席信息官的作用
  20. 什么是“网络空间安全”?这个行业就业方面如何?

热门文章

  1. ARINC429总线收发器 -- HI-3593调试记录
  2. 十次方需求分析与技术架构、Node.js、包资源管理器NPM、Webpack
  3. 数值分析1_拉格朗日插值法牛顿插值法
  4. ArcMap将png图像矢量化
  5. Matlab 马莉,MATLAB数学实验与建模
  6. java layout组件居中_Android 布局中 如何使控件居中
  7. 工程力学(5)—平面任意力系简化与平衡
  8. 使用OAuth保护REST API并使用简单的Angular客户端
  9. 生成 Excel + PDF 导出,用 Java 怎么实现?
  10. excel连接mysql_Excel连接MySQL数据库的方法总结(备查,但暂时用不上)