1. av_opt_set_defaults()
av_opt_set_defaults() 声明:
- 所属库:libavutil(lavu),由于该函数属于lavu这个库,可以想见是个ffmpeg通用的功能
- 头文件:libavutil/opt.h
- 作用:“Set the values of all AVOption fields to their default values.”,注意这个入参的说明,入参对象的第一个成员必须是AVClass对象的指针。
/** * Set the values of all AVOption fields to their default values. * * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) */ void av_opt_set_defaults(void *s); /** * Set the values of all AVOption fields to their default values. Only these * AVOption fields for which (opt->flags & mask) == flags will have their * default applied to s. * * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) * @param mask combination of AV_OPT_FLAG_* * @param flags combination of AV_OPT_FLAG_* */ void av_opt_set_defaults2(void *s, int mask, int flags);
av_opt_set_defaults() 源码:
- 源文件:libavutil/opt.c
- 作用:一言以蔽之,就是不断取出对应的AVOption对象,将AVOption对象中存储的初始值赋值给s对象(此处为AVFormatContext)的对应的成员
- av_opt_set_defaults() 直接调用了 av_opt_set_defaults2(),而该函数逻辑也很简单:见源码注释以及后续文字解释。
void av_opt_set_defaults(void *s) { av_opt_set_defaults2(s, 0, 0); } void av_opt_set_defaults2(void *s, int mask, int flags) { const AVOption *opt = NULL; while ((opt = av_opt_next(s, opt))) { // 获取AVOption对象 // s->av_class->option与s的成员是对应关系; // AVOption的offset属性定义了s对象对应的成员相对于s对象首地址的偏移offset, // 从而求得该AVOption所映射的s对象成员的地址dst void *dst = ((uint8_t*)s) + opt->offset; // mask和flags用以控制需要修改设置哪些参数 if ((opt->flags & mask) != flags) continue; // 如果属性是只读,那么不设置 if (opt->flags & AV_OPT_FLAG_READONLY) continue; // 根据AVOption对象的type属性可以映射的s对象的成员的类型 // 根据不同类型,调用不同的函数将AVOption的default_val属性提供的默认值 // 来设置s的对象的对应成员。 switch (opt->type) { case AV_OPT_TYPE_CONST: /* Nothing to be done here */ break; case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_CHANNEL_LAYOUT: case AV_OPT_TYPE_PIXEL_FMT: case AV_OPT_TYPE_SAMPLE_FMT: write_number(s, opt, dst, 1, 1, opt->default_val.i64); break; case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_FLOAT: { double val; val = opt->default_val.dbl; write_number(s, opt, dst, val, 1, 1); } break; case AV_OPT_TYPE_RATIONAL: { AVRational val; val = av_d2q(opt->default_val.dbl, INT_MAX); write_number(s, opt, dst, 1, val.den, val.num); } break; case AV_OPT_TYPE_COLOR: set_string_color(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_STRING: set_string(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_IMAGE_SIZE: set_string_image_size(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_VIDEO_RATE: set_string_video_rate(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_BINARY: set_string_binary(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_DICT: /* Cannot set defaults for these types */ break; default: av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n", opt->type, opt->name); } } }
- 在3.2.1中我们已经分析了AVFormatContext->AVClass->option被初始化指向了一个静态的AVOption数组,av_opt_next() 作用就是获取下AVFormatContext->AVClass->option数组中,由last指定的AVOption对象的下一个。具体av_opt_next() 如何实现这一点的,见下面源码以及注释:
const AVOption *av_opt_next(const void *obj, const AVOption *last) { const AVClass *class; // 若obj对象为空,自然option也肯定不存在,返回空 if (!obj) return NULL; // 这个是重点: // obj是一个对象的指针,其指向的对象实体的第一个参数是一个指向AVClass对象的指针 // 如下的强制转换就是取出obj第一个参数值,也即指向obj对象关联的AVClass对象的地址 // 赋值给class class = *(const AVClass**)obj; // 如果last为空,也即没有指定AVOption对象 // 并且class不为空,也即obj这个对象第一个参数确实是AVClass对象指针 // 并且AVClass->option不为空,也即指向有效的AVOption数组 // 并且class->option[0].name不为空,也即AVOption数组的第一项的name成员不为空 if (!last && class && class->option && class->option[0].name) return class->option; // 返回AVOption数组的第一个成员 // 如果last不为空,即已被指定 // 并且last[1].name不为空,即注意理解这个last[1]的数组操作:last指向的AVOption的下一个AVOption的name成员不为空。 if (last && last[1].name) return ++last; // 返回AVOtion数组的last的下一个AVOption,注意一般AVOption数组的最后一项是NULL。 // 若之前没找到合适的AVOption,那么返回NULL return NULL; }
- 取得AVOption选项后,由于AVOption对象与s对象的成员处于映射关系,一个AVOption对象映射到s的一个成员:AVOption对象的offset属性存储着对应成员相对于s首地址的偏移offset,因此可以根据s的地址以及offset得到对应的成员;AVOption对象的default_val属性存储着对应成员的默认值;AVOption对象的type属性存储着对应成员的类型;由上述三个属性就可以可以s对象的相应成员赋默认值,当然对于不同类型的成员,还需要调用不同的方法,见源码,这儿不展开论述。
- 上述过程涉到ffmpeg中很重要的两个结构体AVClass && AVOption,以及相关的set_tring_*和write_number函数。会在另外一篇文章(FFMPEG4.1源码解析之 AVClass结构体 && AVOption结构体)中做专门的阐述。