AVOption用于描述结构体中的成员变量。它最主要的作用可以概括为两个字:“赋值”。
一个AVOption结构体包含了变量名称,简短的帮助,取值等信息。
所有和AVOption有关的数据都存储在AVClass结构体中。如果一个结构体(例如AVFormatContext或者AVCodecContext)想要支持AVOption的话,它的第一个成员变量必须是一个指向AVClass结构体的指针。该AVClass中的成员变量option必须指向一个AVOption类型的静态数组。
何为AVOption?
AVOption是用来设置FFmpeg中变量值的结构体。特点就在于它赋值的灵活性。AVOption可以使用字符串为任何类型的变量赋值。统一使用字符串赋值。例如给int型变量qp设定值为20,通过AVOption需要传递进去一个内容为“20”的字符串。此外,AVOption中变量的名称也使用字符串来表示。传递两个字符串(一个是变量的名称,一个是变量的值)就可以改变系统中变量的值。
对于从外部系统中调用FFmpeg的人来说,作用就很大了:从外部系统中只可以传递字符串给内部系统。比如说对于直接调用ffmpeg.exe的人来说,他们是无法修改FFmpeg内部各个变量的数值的,这种情况下只能通过输入“名称”和“值”这样的字符串,通过AVOption改变FFmpeg内部变量的值。由此可见,使用AVOption可以使FFmpeg更加适应多种多样的外部系统。如互联网上只可以传输字符串。
其实除了可以对FFmpeg常用结构体AVFormatContext,AVCodecContext等进行赋值之外,还可以对它们的私有数据priv_data进行赋值。例如使用libx264进行编码的时候,通过AVCodecContext的priv_data字段可以对X264Context结构体中的变量进行赋值,设置preset,profile等。使用libx265进行编码的时候,通过AVCodecContext的priv_data字段可以对libx265Context结构体中的变量进行赋值,设置preset,tune等。
何为AVClass?
AVClass最主要的作用就是给结构体(例如AVFormatContext等)增加AVOption功能的支持。AVClass就是AVOption和目标结构体之间的“桥梁”。AVClass要求必须声明为目标结构体的第一个变量。
AVClass中有一个option数组用于存储目标结构体的所有的AVOption。举个例子,AVFormatContext结构体,AVClass和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_next = format_child_class_next,
.category = AV_CLASS_CATEGORY_MUXER,
.get_category = get_category,
};
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},
AVOption
- /**
- * AVOption
- */
- typedef struct AVOption {
- const char *name; 名称。
- /**
- * short English help text
- * @todo What about other languages?
- */
- const char *help; 简短的帮助。
- /**
- * The offset relative to the context structure where the option
- * value is stored. It should be 0 for named constants.
- */
- int offset; 选项相对结构体首部地址的偏移量(这个很重要)。
- enum AVOptionType type; 选项的类型。
- /**
- * the default value for scalar options
- */
- 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 option 选项的最小值。
- double max; ///< maximum valid value for the option 选项的最大值。
- int flags; 一些标记。
- /**
- * The logical unit to which the option belongs. Non-constant
- * options and corresponding named constants share the same
- * unit. May be NULL.
- */
- const char *unit; 该选项所属的逻辑单元,可以为空。
- } AVOption;
其中,default_val是一个union类型的变量,可以根据选项数据类型的不同,取int,double,char*,AVRational(表示分数)几种类型。
AVClass
AVClass中存储了AVOption类型的数组option,用于存储选项信息。AVClass有一个特点就是它必须位于其支持的结构体的第一个位置。- /**
- * Describe the class of an AVClass context structure. That is an
- * arbitrary struct of which the first field is a pointer to an
- * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.).
- */
- typedef struct AVClass {
- /**
- * The name of the class; usually it is the same name as the
- * context structure type to which the AVClass is associated.
- */
- const char* class_name; AVClass名称。
- /**
- * A pointer to a function which returns the name of a context
- * instance ctx associated with the class.
- */
- const char* (*item_name)(void* ctx);函数,获取与AVClass相关联的结构体实例的名称。
- /**
- * a pointer to the first option specified in the class if any or NULL
- *
- * @see av_set_default_options()
- */
- const struct AVOption *option; AVOption类型的数组(最重要)。
- /**
- * LIBAVUTIL_VERSION with which this structure was created.
- * This is used to allow fields to be added without requiring major
- * version bumps everywhere.
- */
- int version; 完成该AVClass的时候的LIBAVUTIL_VERSION。
- /**
- * Offset in the structure where log_level_offset is stored.
- * 0 means there is no such variable
- */
- int log_level_offset_offset;
- /**
- * Offset in the structure where a pointer to the parent context for
- * logging is stored. For example a decoder could pass its AVCodecContext
- * to eval as such a parent context, which an av_log() implementation
- * could then leverage to display the parent context.
- * The offset can be NULL.
- */
- int parent_log_context_offset;
- /**
- * Return next AVOptions-enabled child or NULL
- */
- void* (*child_next)(void *obj, void *prev);
- /**
- * Return an AVClass corresponding to the next potential
- * AVOptions-enabled child.
- *
- * The difference between child_next and this is that
- * child_next iterates over _already existing_ objects, while
- * child_class_next iterates over _all possible_ children.
- */
- const struct AVClass* (*child_class_next)(const struct AVClass *prev);
- /**
- * Category used for visualization (like color)
- * This is only set if the category is equal for all objects using this class.
- * available since version (51 << 16 | 56 << 8 | 100)
- */
- AVClassCategory category; AVClass的类型,是一个类型为AVClassCategory的枚举型变量。
- /**
- * Callback to return the category.
- * available since version (51 << 16 | 59 << 8 | 100)
- */
- AVClassCategory (*get_category)(void* ctx);
- /**
- * Callback to return the supported/allowed ranges.
- * available since version (52.12)
- */
- int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags);
- } AVClass;
下面通过具体的例子看一下AVClass这个结构体。我们看几个具体的例子:
- AVFormatContext中的AVClass
- AVCodecContext中的AVClass
- AVFrame中的AVClass
- 各种组件(libRTMP,libx264,libx265)里面特有的AVClass。