Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1852978
  • 博文数量: 274
  • 博客积分: 2366
  • 博客等级: 大尉
  • 技术积分: 1880
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-22 09:37
文章分类

全部博文(274)

文章存档

2022年(1)

2020年(10)

2019年(7)

2018年(18)

2017年(26)

2016年(32)

2015年(43)

2014年(30)

2013年(44)

2012年(36)

2011年(17)

2010年(10)

分类: 其他平台

2014-07-30 11:22:21

AVClass 和 AVOption


先看它们的定义


/**
 * 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;


    /**
     * A pointer to a function which returns the name of a context
     * instance ctx associated with the class.
     */
    const char* (*item_name)(void* ctx);


    /**
     * a pointer to the first option specified in the class if any or NULL
     *
     * @see av_set_default_options()
     */
    const struct AVOption *option;


    /**
     * 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;


    /**
     * 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 loging is stored.
     * for example a decoder that uses eval.c could pass its AVCodecContext to eval as such
     * parent context. And a av_log() implementation could then display the parent context
     * can be NULL of course
     */
    int parent_log_context_offset;


    /**
     * Return next AVOptions-enabled child or NULL
     */
    void* (*child_next)(void *obj, void *prev);


    /**
     * Return an AVClass corresponding to 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);
} AVClass;
  
/**
 * 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 {
        double dbl;
        const char *str;
        /* TODO those are unused now */
        int64_t i64;
        AVRational q;
    } default_val;
    double min;                 ///< minimum valid value for the option
    double max;                 ///< maximum valid value for the option


    int flags;
#define AV_OPT_FLAG_ENCODING_PARAM  1   ///< a generic parameter which can be set by the user for muxing or encoding
#define AV_OPT_FLAG_DECODING_PARAM  2   ///< a generic parameter which can be set by the user for demuxing or decoding
#define AV_OPT_FLAG_METADATA        4   ///< some data extracted or inserted into the file like title, comment, ...
#define AV_OPT_FLAG_AUDIO_PARAM     8
#define AV_OPT_FLAG_VIDEO_PARAM     16
#define AV_OPT_FLAG_SUBTITLE_PARAM  32
//FIXME think about enc-audio, ... style 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;


AVOption 是视音频的一个选项, 这个结构通常先定义为一个指针数组, 最后一个entry必须为NULL,
方便遍历,然后由AVClass 里面的指针指向. AVOption有名字, 类型, flags, default_val(缺省值) 之类的字段, 缺省值类型多样, 有浮点型, 字符串性, 长整型,分数性等.
注意到里面有个offset 字段, 这个字段是保持参数在上下文(context)的中的偏移量, 可以定位到参数实际存储位置.正如注释里面提到, 常量类型参数该字段为值为0,可参考后面的例子看下该字段的确切含义.

AVClass 是视音频的基础类(可以想象为c++的基类), 必须都是放一些大的数据结构的
第一个字段,才能使用av_opt之类的api
typedef struct AVFormatContext {
    /**
     * A class for logging and AVOptions. Set by avformat_alloc_context().
     * Exports (de)muxer private options if they exist.
     */
    const AVClass *av_class;
     .....
}


里面重要的字段是保存AVOption 指针(option)和遍历指针指向一组数据的方法(child_next和child_class_next), 每个大类都会定义自己的AVClass, 如
static const AVClass av_format_context_class = {
    .class_name     = "AVFormatContext",
    .item_name      = format_to_name,
    .option         = options,
    .version        = LIBAVUTIL_VERSION_INT,
    .child_next     = format_child_next,
    .child_class_next = format_child_class_next,
};
opt.h 开始部分对如何使用av_opt之类的操作api 描述的比较详细
我们可以从opt.c 后面的测试程序看它们的使用流程, 如下


#ifdef TEST


#undef printf


typedef struct TestContext
{
    const AVClass *class;
    int num;
    int toggle;
    char *string;
    int flags;
    AVRational rational;
} TestContext;


#define OFFSET(x) offsetof(TestContext, x)


#define TEST_FLAG_COOL 01
#define TEST_FLAG_LAME 02
#define TEST_FLAG_MU   04


static const AVOption test_options[]= {
{"num",      "set num",        OFFSET(num),      AV_OPT_TYPE_INT,      {0},              0,        100                 },
{"toggle",   "set toggle",     OFFSET(toggle),   AV_OPT_TYPE_INT,      {0},              0,        1                   },
{"rational", "set rational",   OFFSET(rational), AV_OPT_TYPE_RATIONAL, {0},              0,        10                  },
{"string",   "set string",     OFFSET(string),   AV_OPT_TYPE_STRING,   {0},              CHAR_MIN, CHAR_MAX            },
{"flags",    "set flags",      OFFSET(flags),    AV_OPT_TYPE_FLAGS,    {0},              0,        INT_MAX, 0, "flags" },
{"cool",     "set cool flag ", 0,                AV_OPT_TYPE_CONST,    {TEST_FLAG_COOL}, INT_MIN,  INT_MAX, 0, "flags" },
{"lame",     "set lame flag ", 0,                AV_OPT_TYPE_CONST,    {TEST_FLAG_LAME}, INT_MIN,  INT_MAX, 0, "flags" },
{"mu",       "set mu flag ",   0,                AV_OPT_TYPE_CONST,    {TEST_FLAG_MU},   INT_MIN,  INT_MAX, 0, "flags" },
{NULL},
};


static const char *test_get_name(void *ctx)
{
    return "test";
}


static const AVClass test_class = {
    "TestContext",
    test_get_name,
    test_options
};


int main(void)
{
    int i;


    printf("\nTesting av_set_options_string()\n");
    {
        TestContext test_ctx;
        const char *options[] = {
            "",
            ":",
            "=",
            "foo=:",
            ":=foo",
            "=foo",
            "foo=",
            "foo",
            "foo=val",
            "foo==val",
            "toggle=:",
            "string=:",
            "toggle=1 : foo",
            "toggle=100",
            "toggle==1",
            "flags=+mu-lame : num=42: toggle=0",
            "num=42 : string=blahblah",
            "rational=0 : rational=1/2 : rational=1/-1",
            "rational=-1/0",
        };


        test_ctx.class = &test_class;
        av_opt_set_defaults(&test_ctx);
        test_ctx.string = av_strdup("default");


        av_log_set_level(AV_LOG_DEBUG);


        for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
            av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
            if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
                av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
            printf("\n");
        }
    }


    return 0;
}


#endif


总结: 这里其实还有一个大主角context 未出场, avclass 为context 收集一些参数(context 字段)的信息并存储在avoption里面, 这样可以达到以名字来查找修改context 字段的目的, 确实是不错的一个手段啊!

阅读(3880) | 评论(0) | 转发(0) |
0

上一篇:struct AVDictionary av字典

下一篇:linux if命令

给主人留下些什么吧!~~