【FFMPEG源码分析】ffmpeg中context与AVClass,AVOption之间的关系
通过前面三篇文章的分析大致了解了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之间的关系相关推荐
- FFMPEG源码分析(一)
FFMPEG源码分析(一) ffmpeg之前公司项目中就使用过,但是多停留于应用层面,实现某个功能时,需要哪些结构体以及调用哪些函数.最近想系统的学习一下ffmpeg,于是开始看雷霄骅https:// ...
- FFMPEG源码分析(二)
ffmpeg源码分析之数据流 本文主要介绍ffmpeg的数据流,在ffmpeg中主要分有三个主要用途用于媒体流的解码播放,媒体流的转换(解码之后再编码)和媒体流录制. 媒体流的解码播放 在ffmpeg ...
- FFMPEG 源码分析
FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库.FFMPEG是在linux下开发的,但也有windows下的编译版本. ffmpeg项目由以下几部分组 ...
- ffmpeg源码分析-parse_optgroup
本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...
- ffmpeg源码分析-ffmpeg_parse_options
本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...
- ffmpeg源码分析-transcode_step
本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...
- FFmpeg源码分析-直播延迟-内存泄漏
FFmpeg源码分析-直播延迟-内存泄漏|FFmpeg源码分析方法|ffmpeg播放为什么容易产生延迟|解复用.解码内存泄漏分析 专注后台服务器开发,包括C/C++,Linux,Nginx,ZeroM ...
- ffmpeg源码分析与应用示例(一)——H.264解码与QP提取
本文包含以下内容 1.H.264解码流程详述与对应ffmpeg源码解析 2.针对一个应用实例介绍通过修改ffmpeg源码解决问题的方案 具有较强的综合性. 先介绍一下在第二部分中将要解决的实际问题:自 ...
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
最新文章
- 堆排序算法的java实现_堆排序算法的JAVA实现
- 今日头条 文章采集_我在今日头条的成长之路—文章的排版与结构
- 别看360完成私有化 仍有三因素阻碍中概股回归
- linux下各种小命令
- 随手小记 才知道[阁楼藏尸|未来闪影]
- 机器学习实战(一)k-近邻kNN(k-Nearest Neighbor)
- itextpdf添加表格元素_基操勿6第四期:PPT表格美化
- java将jfif格式转换成ipg_无需工具直接将jfif格式图片批量修改为jpg格式图片的方法...
- MATLAB Cholesky分解
- Linux系统下LightDM详解
- 微信 dat 文件还原
- node生成唯一设备id(node-machine-id)
- 中考可以使用计算机吗,2017年中考可以带计算器吗
- 【C语言/入门游戏】猜数字,关机指令游戏及go to语句
- “双碳”背景下,消费金融如何抓住“绿色”机遇?
- Dell precision 7720 移动工作站 nvidia 显卡安装说明
- 游戏skr而止,漏洞周而复始 —— 游戏合约漏洞全面汇总 | 漏洞分析连载之六
- 日报2015/11/11(第一行代码读书笔记)
- 数字化和社会化商业转型中首席信息官的作用
- 什么是“网络空间安全”?这个行业就业方面如何?
热门文章
- ARINC429总线收发器 -- HI-3593调试记录
- 十次方需求分析与技术架构、Node.js、包资源管理器NPM、Webpack
- 数值分析1_拉格朗日插值法牛顿插值法
- ArcMap将png图像矢量化
- Matlab 马莉,MATLAB数学实验与建模
- java layout组件居中_Android 布局中 如何使控件居中
- 工程力学(5)—平面任意力系简化与平衡
- 使用OAuth保护REST API并使用简单的Angular客户端
- 生成 Excel + PDF 导出,用 Java 怎么实现?
- excel连接mysql_Excel连接MySQL数据库的方法总结(备查,但暂时用不上)