FFMPEG4.1源码分析之 av_opt_set_defaults()函数

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);
            }
        }
    }
  1.  在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;
    }
  2. 取得AVOption选项后,由于AVOption对象与s对象的成员处于映射关系,一个AVOption对象映射到s的一个成员:AVOption对象的offset属性存储着对应成员相对于s首地址的偏移offset,因此可以根据s的地址以及offset得到对应的成员;AVOption对象的default_val属性存储着对应成员的默认值;AVOption对象的type属性存储着对应成员的类型;由上述三个属性就可以可以s对象的相应成员赋默认值,当然对于不同类型的成员,还需要调用不同的方法,见源码,这儿不展开论述。
  3. 上述过程涉到ffmpeg中很重要的两个结构体AVClass && AVOption,以及相关的set_tring_*和write_number函数。会在另外一篇文章(FFMPEG4.1源码解析之 AVClass结构体 && AVOption结构体)中做专门的阐述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值