• 何为AVOption?AVClass? 及其关联的若干个Context


    何为AVOption?AVClass? 及其关联的若干个Context
    ----------------------------------------
    author:hjjdebug
    date: 2022年 09月 30日 星期五 20:17:50 CST
    ----------------------------------------

    AVOption 是一个结构,它的每一个实例,用来描述AVContext 中一个成员变量.
    这一句话挺抽象的,包含了不少信息.

    AVContext 当然也是一个结构, 是用户自定义的一个结构。 c语言也就只有结构了.
    我们随便定义这个结构,但是要求它的第一个成员是AVClass 指针.
    又是挺关键的一句话.

    举个例子吧:
    typedef struct TestContext {
        const AVClass *class;
        char *person;        //用AVOption opt_person 来描述,  也可以叫opt[1]或其它名字
        int  telenum;        //用AVOption opt_tele 来描述,  也可以叫opt[2]或其它名字
        int   flags;        //用AVOption opt_flags 来描述, 也可以叫opt[3]或其它名字
    }

    opt_person 可能需要如下信息来表达:
    ctx中有一个成员,它的名字叫"person",它的默认值是"张三",它在ctx偏移是offset(ctx,person),它是个char*型变量, 表示人员的名称
    opt_telenum 可能需要如下信息来表达:
    ctx中有一个成员,它的名字叫telenum,它的默认值是12345678,它在ctx偏移是offset(num,telenum),它是个整型变量, 代表电话号码
    opt_flags 可能需要如下信息来表达:
    ctx中有一个成员,它的名字叫flags,它的默认值是0x5,它在ctx偏移是offset(num,flag),它是个int型变量,具体意义参考flags比特位定义

    有了这个认识,我们来定义一下AVOpton 结构,直接看一下ffmpeg 中的定义吧。 这下就看懂了.
      type = struct AVOption {
          const char *name;        // 定义一个结构变量名称
          const char *help;        // 对这个名称可以进一步解释,这是给人看的
          int offset;            // 计算机找成员不看文字,它要找偏移
          enum AVOptionType type;    // 类型说明,说明是整形,实型,布尔型及其它型请看代码定义
          union {                // 数据类型的一个联合,储存默认的数值,其类型有 type 决定
              int64_t i64;
              double dbl;
              const char *str;
              AVRational q;
          } default_val;
          double min;            //数据有效值的最大值,最小值范围
          double max;
          int flags;            //定义了是否是编码参数,解码参数,音频参数,视频参数等信息,可以认为是使用类型,具体请看代码定义
          const char *unit;        //属于那个单元(部门)
      }
      下面我们用c代码定义3个AVOption对象

    static const AVOption test_class_options[]= {
        {"person",     "set person name",         OFFSET(person),         AV_OPT_TYPE_STRING,         { .str = "张三" },       CHAR_MIN,  CHAR_MAX, 1 },
        {"telenum",    "set telephone num",       OFFSET(telenum),        AV_OPT_TYPE_INT,            { .i64 = 12345678 },     INT_MIN, INT_MAX, 1, NULL},
        {"flags",      "set flags",               OFFSET(flags),          AV_OPT_TYPE_FLAGS,          { .i64 = 1 },             0,   INT_MAX, 1, "flags" },
    }

    将以上 test_class_options 选项用AVClass 对象来包含.
    static const AVClass test_class = {
        .class_name = "TestContext",
        .option     = test_class_options,
        ... 其它项还有其它功能,例如层级划分等,这里都不考虑,给默认值了.
    };

    使用举例:
        TestContext test_ctx = { 0 }; //声明一个ctx 对象, 它包含一个AVClass 指针, 这个ctx会有很多成员变量,每个成员变量都会有一个AVOption 项与之对应
        test_ctx.class = &test_class; // 为这个AVClass 指针赋值,这个AVClass对象会包含一个AVOption 指针,AVOption 中定义了所有默认变量数值。
        av_opt_set_defaults(&test_ctx); //然后可以为这个ctx所有其它变量付初始值, 初始值就是AVOption 项中定义的, 一个函数调用就全部赋值完成了,很强大!

            //然后你可以用一般的方法printf, 打印出ctx中各成员变量的值
            //当然也可以用它写的专有函数,打印内部信息,例如:   av_opt_show2(&test_ctx, NULL, -1, 0);
            //发现还是其内部写的函数,打印的漂亮!打印了选项的名称,数值类型,说明及它属于什么使用类型

    自然,为了灵活的操控这些成员变量,av_opt还定义有其它函数, av_opt_get, av_opt_set, av_opt_find... 等
    阅读一下libavutil/opt.c 会让你受益匪浅,尤其是代码跟入之后可了解其全部细节.
    它演示了全部用字符串来修改成员的值及程序判错功能.  只所以它能统一用字符串输入,是因为它内部有一个系列分别对应不同的类型解析.
    也演示了对象的序列化输入,输出. 就是用一个长字符串来操作对象(get,set),这就是字符串切分和合并的问题了.
    这样你可以了解AVOption 结构,并大致了解AVClass 结构及如何客户化一些Context结构.

    重点:
    AVOption是用来描述Context成员的结构
    AVClass是用来描述Context结构的结构
    ffmpeg 有400多个AVClass 对象, 意味着有400多种结构.

    参考: 1. libavutil/tests/opt.c 代码
    参考: 2. ffmpeg 相关代码

    实例胜千言,放上我自己的测试代码:

    1. #include
    2. #include
    3. #include
    4. #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
    5. //第一个成员是AVClass 指针的类叫context 类,
    6. //换句话说, AVClass 是描述任意context类的结构, 它要放在context类的第一个成员位置.
    7. typedef struct stTestContext {
    8. const AVClass *class;
    9. char *person; //用AVOption opt_person 来描述, 也可以叫opt[1]或其它名字
    10. int telenum; //用AVOption opt_tele 来描述, 也可以叫opt[2]或其它名字
    11. int flags; //用AVOption opt_flags 来描述, 也可以叫opt[3]或其它名字
    12. }TestContext;
    13. //由于定义了类型, 表格中可以使用不同的数据类型, 用表格为成员赋初值.
    14. #define OFFSET(x) offsetof(TestContext, x)
    15. static const AVOption test_class_options[]= {
    16. {"person", "set person name", OFFSET(person), AV_OPT_TYPE_STRING, { .str = "张三" }, CHAR_MIN, CHAR_MAX, 1 },
    17. {"telenum", "set telephone num", OFFSET(telenum), AV_OPT_TYPE_INT, { .i64 = 12345678 }, INT_MIN, INT_MAX, 1, NULL},
    18. {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = 1 }, 0, INT_MAX, 1, "flags" },
    19. };
    20. static const AVClass test_class = {
    21. .class_name = "TestContext",
    22. .option = test_class_options,
    23. };
    24. TestContext tst_ctx;
    25. int main()
    26. {
    27. tst_ctx.class = &test_class;
    28. av_opt_set_defaults(&tst_ctx); // 定义了表格,一个函数调用就完成了所有变量的赋值!,就是为了爽这一下!
    29. printf("persion:%s\n",tst_ctx.person);
    30. printf("telenum:%d\n",tst_ctx.telenum);
    31. printf("flags:%d\n",tst_ctx.flags);
    32. return 0;
    33. }

  • 相关阅读:
    Unity基础课程之物理引擎2-碰撞检测案例-吃金币并加分
    【编译原理】语法分析
    华为云云耀云服务器L实例评测|教你搭建第一个Java程序
    ZMQ之高可靠对称节点--双子星模式
    项目上线计划表
    拖放操作-拖动文件直接在窗口中显示文件内容
    uni-app 使用 webview运行到小程序,打开萤石云视频
    数学公式与随机数
    表格分组标签:表格行分组中的隐藏功能
    怕客户跑单?这套上市制造企业都在使的订单管理方案你一定要看看
  • 原文地址:https://blog.csdn.net/hejinjing_tom_com/article/details/127128742