美文网首页
ffmpeg结构体解析-AVClass 和 AVOption

ffmpeg结构体解析-AVClass 和 AVOption

作者: kotlon | 来源:发表于2020-12-20 21:55 被阅读0次

    在 AVFormatContext 或者 AVCodecContext 等类里面,第一个字段都是 AVClass 指针,以AVFormatContext示例,如下:

    //avformat.h
    typedef struct AVFormatContext {
        /**
         * A class for logging and @ref avoptions. Set by avformat_alloc_context().
         * Exports (de)muxer private options if they exist.
         */
        const AVClass *av_class;
        //省略其它代码
    

    根据API的介绍,AVClass 就是一个用于打印log 和AVOption的引用,由avformat_alloc_context() 函数创建。怎么理解这个引用呢?

    就是说,AVClass 建立起了 AVOption 和 Context 之间的桥梁。

    AVOption 结构体

    那么这样一说,必须先来看下 AVOption 这个结构体。

    先看 API 对 AVOption 结构体的说明,如下:

    * AVOptions provide a generic system to declare options on arbitrary structs
    * ("objects"). An option can have a help text, a type and a range of possible
    * values. Options may then be enumerated, read and written to.
    *
    * @section avoptions_implement Implementing AVOptions
    * This section describes how to add AVOptions capabilities to a struct.
    *
    * All AVOptions-related information is stored in an AVClass. Therefore
    * the first member of the struct should be a pointer to an AVClass describing it.
    * The option field of the AVClass must be set to a NULL-terminated static array
    * of AVOptions. Each AVOption must have a non-empty name, a type, a default
    * value and for number-type AVOptions also a range of allowed values. It must
    * also declare an offset in bytes from the start of the struct, where the field
    * associated with this AVOption is located. Other fields in the AVOption struct
    * should also be set when applicable, but are not required.
    

    AVOption 提供了一种泛型系统用于描述任意结构体的 Option。所有 AVOption 相关的信息都是存储在 AVClass 里面的。因此所以AVOption 描述的结构体的第一个字段必定是 AVClass,其次AVClass 必须包含一个静态的 AVOption 数组。

    AVOption 的定义在 libutils/opts.h 头文件中,如下:

    /**
     * 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;
    #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_AUDIO_PARAM     8
    #define AV_OPT_FLAG_VIDEO_PARAM     16
    #define AV_OPT_FLAG_SUBTITLE_PARAM  32
    /**
     * The option is intended for exporting values to the caller.
     */
    #define AV_OPT_FLAG_EXPORT          64
    /**
     * The option may not be set through the AVOptions API, only read.
     * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set.
     */
    #define AV_OPT_FLAG_READONLY        128
    #define AV_OPT_FLAG_BSF_PARAM       (1<<8) ///< a generic parameter which can be set by the user for bit stream filtering
    #define AV_OPT_FLAG_RUNTIME_PARAM   (1<<15) ///< a generic parameter which can be set by the user at runtime
    #define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering
    #define AV_OPT_FLAG_DEPRECATED      (1<<17) ///< set if option is deprecated, users should refer to AVOption.help text for more information
    #define AV_OPT_FLAG_CHILD_CONSTS    (1<<18) ///< set if option constants can also reside in child objects
    //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 结构体的字段:

    • const char *name:Context Struc 结构体的字段名称

    • const char *help:帮助说明

    • int offset:表示该字段在结构体中的偏移量,一般可以使用 C标准库的 offsetof(type, member-designator) 计算该字体在结构体中的偏移量

    • enum AVOptionType type:枚举值,表示该字段的类型,后面讲解

    • default_val: 默认数值,可以是 int,double,字符串任意类型。

    • min max:这两个字段表示取值范围,限定了该字段的取值范围

    • int flags:类型标记位,取值如描述

    • const char *unit:该选项所属的逻辑单元,可以为空

    AVClass

    先来看 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;
    
        /**
         * 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
         * 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;
    
        /**
         * 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;
    

    根据 API 的意思,AVClass 就是用于描述任意包含 AVClass 的一个 Context 的信息类,并且会出现在该 Context 类的第一个字段。然后看下 AVClass 结构体的字段如下:

    • const char* class_name:表示Context 类的名称,一般和描述的 Context 类的类名/结构体名一致

    • const char* (item_name)(void ctx):可以返回该 Context 类实例的一个函数

    • const struct AVOption *option:AcOption 数组

    • version:创建该结构体的版本号

    • log_level_offset_offset:表示 level_offset_offset 字段在这个结构体的偏移量,如果没有这个字段则为0

    • parent_log_context_offset:同上,表示的是 Parent Context 的 level_offset_offset 字段在这个结构体的偏移量

    • void* (*child_next)(void *obj, void *prev):一个返回下一个 AVOption 的函数指针

    • const struct AVClass* (*child_class_next)(const struct AVClass *prev)

    • AVClassCategory category:表示 AVClass 的类型,是一组枚举类型的值,见后面备注。

    • AVClassCategory (get_category)(void ctx):

    • int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags):

    AVoption 使用

    根据之前 API 的描述, AVOption 是描述任意的结构体,提供一种泛型能力。

    现在来看下怎么使用 AVOption 来描述我们自己的结构体。

    首先,我们按照在头文件定义一些结构体或者 const 常量:

    #include <libavutil/log.h>
    
    //定义的 Context 类型结构体,包含一个 AVClass 指针
    typedef struct test_context_struct {
        AVClass aClass;
        int mId;
        char *name;
    } test_struct;
    
    //作为 AVClass 里面的 AVOption
    static const AVOption test_options[] = {
            {"test_int",  "A Int filed,for id",          offsetof(test_struct,
                                                                  mId), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX},
            {"test_name", "A char array filed,for name", offsetof(test_struct, name)}
    
    };
    
    static const AVClass test_av_class = {
            .class_name = "test_av_class",
            .item_name = av_default_item_name,
            .option = test_options,
            .version = LIBAVUTIL_VERSION_INT
    
    };
    

    然后定义相关的函数:

    #include <libavutil/opt.h>
    test_struct *alloc_test_struct(void) {
        test_struct *testStruct = static_cast<test_struct *>(av_mallocz(sizeof(*testStruct)));
        testStruct->aClass = test_av_class;
        av_opt_set_defaults(testStruct);
        return testStruct;
    }
    
    void free_test_struct(test_struct *testStruct) {
        av_opt_free(testStruct);
        av_free(testStruct);
    }
    

    最终,使用的使用,你可以使用 alloc_test_struct() 函数获得默认的一个结构体对象,如下:

    test_struct* context_struct = alloc_test_struct();
    

    AVFormatContext 分析

    我们可以通过 avformat_alloc_context() 函数获取一个默认的 AVFormatContext 对象,如下:

    AVFormatContext *avFormatContext;
    avformat_network_init();
    //ffmpeg 4.0 之后可以忽略这个函数
    av_register_all();
    avFormatContext = avformat_alloc_context();
    

    avformat_alloc_context() 函数位于 libavformat/option.c 下,如下:

    AVFormatContext *avformat_alloc_context(void)
    {
        AVFormatContext *ic;
        AVFormatInternal *internal;
        ic = av_malloc(sizeof(AVFormatContext));
        if (!ic) return ic;
    
        internal = av_mallocz(sizeof(*internal));
        if (!internal) {
            av_free(ic);
            return NULL;
        }
        avformat_get_context_defaults(ic);
        ic->internal = internal;
        ic->internal->offset = AV_NOPTS_VALUE;
        ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
        ic->internal->shortest_end = AV_NOPTS_VALUE;
    
        return ic;
    }
    

    前面的逻辑主要是分配申请内存,关键是 avformat_get_context_defaults() 这一行代码,如下:

    static void avformat_get_context_defaults(AVFormatContext *s)
    {
        memset(s, 0, sizeof(AVFormatContext));
    
        s->av_class = &av_format_context_class;
    
        s->io_open  = io_open_default;
        s->io_close = io_close_default;
    
        av_opt_set_defaults(s);
    }
    

    这个avformat_get_context_defaults()函数里面,通过调用 av_format_context_class 这个 Const 常量对象,给 AVFormatContext 对象的类型为 AVClass 的 av_class 字段赋值,然后对 io_open 和 io_close 赋值,最后使用 av_opt_set_defaults() 对 AVFormatContex 进行初始化赋值。

    其中,av_format_context_class 常量定义在 libavutil/opt.c 文件下。

    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,
    #if FF_API_CHILD_CLASS_NEXT
        .child_class_next = format_child_class_next,
    #endif
        .child_class_iterate = format_child_class_iterate,
        .category       = AV_CLASS_CATEGORY_MUXER,
        .get_category   = get_category,
    };
    

    关键字段介绍如下:

    • item_name 调用的是 option.c 里面的 format_to_name() 函数

      static const char* format_to_name(void* ptr)
      {
          AVFormatContext* fc = (AVFormatContext*) ptr;
          if(fc->iformat) return fc->iformat->name;
          else if(fc->oformat) return fc->oformat->name;
          else return "NULL";
      }
      

      会依次从 iformat,oformat 里面取出name 字段,作为 AVFormatContext 的name,因为每一个 AVFormatContext 只能是Input 或者 Output 其中一个。

    • option 调用的是 avformat_options函数,位于 libavformat/options_table.h.

      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},
      {"formatprobesize", "number of bytes to probe file format", OFFSET(format_probesize), AV_OPT_TYPE_INT, {.i64 = PROBE_BUF_MAX}, 0, INT_MAX-1, D},
      {"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, E},
      {"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = AVFMT_FLAG_AUTO_BSF }, INT_MIN, INT_MAX, D|E, "fflags"},
      {"flush_packets", "reduce the latency by flushing out packets immediately", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, E, "fflags"},
      {"ignidx", "ignore index", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNIDX }, INT_MIN, INT_MAX, D, "fflags"},
      {"genpts", "generate pts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_GENPTS }, INT_MIN, INT_MAX, D, "fflags"},
      {"nofillin", "do not fill in missing values that can be exactly calculated", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOFILLIN }, INT_MIN, INT_MAX, D, "fflags"},
      {"noparse", "disable AVParsers, this needs nofillin too", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOPARSE }, INT_MIN, INT_MAX, D, "fflags"},
      {"igndts", "ignore dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNDTS }, INT_MIN, INT_MAX, D, "fflags"},
      {"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"},
      {"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"},
      #if FF_API_LAVF_KEEPSIDE_FLAG
      {"keepside", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"},
      #endif
      {"fastseek", "fast but inaccurate seeks", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FAST_SEEK }, INT_MIN, INT_MAX, D, "fflags"},
      #if FF_API_LAVF_MP4A_LATM
      {"latm", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"},
      #endif
      {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"},
      {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" },
      {"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" },
      {"autobsf", "add needed bsfs automatically", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_AUTO_BSF }, 0, 0, E, "fflags" },
      {"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D},
      {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D},
      {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D},
      {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D},
      {"rtbufsize", "max memory used for buffering real-time frames", OFFSET(max_picture_buffer), AV_OPT_TYPE_INT, {.i64 = 3041280 }, 0, INT_MAX, D}, /* defaults to 1s of 15fps 352x288 YUYV422 video */
      {"fdebug", "print specific debug info", OFFSET(debug), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, E|D, "fdebug"},
      {"ts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_FDEBUG_TS }, INT_MIN, INT_MAX, E|D, "fdebug"},
      {"max_delay", "maximum muxing or demuxing delay in microseconds", OFFSET(max_delay), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, E|D},
      {"start_time_realtime", "wall-clock time when stream begins (PTS==0)", OFFSET(start_time_realtime), AV_OPT_TYPE_INT64, {.i64 = AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX, E},
      {"fpsprobesize", "number of frames used to probe fps", OFFSET(fps_probe_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX-1, D},
      {"audio_preload", "microseconds by which audio packets should be interleaved earlier", OFFSET(audio_preload), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E},
      {"chunk_duration", "microseconds for each chunk", OFFSET(max_chunk_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E},
      {"chunk_size", "size in bytes for each chunk", OFFSET(max_chunk_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E},
      /* this is a crutch for avconv, since it cannot deal with identically named options in different contexts.
       * to be removed when avconv is fixed */
      {"f_err_detect", "set error detection flags (deprecated; use err_detect, save via avconv)", OFFSET(error_recognition), AV_OPT_TYPE_FLAGS, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, D, "err_detect"},
      {"err_detect", "set error detection flags", OFFSET(error_recognition), AV_OPT_TYPE_FLAGS, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, D, "err_detect"},
      {"crccheck", "verify embedded CRCs", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, D, "err_detect"},
      {"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, D, "err_detect"},
      {"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, D, "err_detect"},
      {"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, D, "err_detect"},
      {"ignore_err", "ignore errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_IGNORE_ERR }, INT_MIN, INT_MAX, D, "err_detect"},
      {"careful",    "consider things that violate the spec, are fast to check and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"},
      {"compliant",  "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_COMPLIANT | AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"},
      {"aggressive", "consider things that a sane encoder shouldn't do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE | AV_EF_COMPLIANT | AV_EF_CAREFUL}, INT_MIN, INT_MAX, D, "err_detect"},
      {"use_wallclock_as_timestamps", "use wallclock as timestamps", OFFSET(use_wallclock_as_timestamps), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, D},
      {"skip_initial_bytes", "set number of bytes to skip before reading header and frames", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX-1, D},
      {"correct_ts_overflow", "correct single timestamp overflows", OFFSET(correct_ts_overflow), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, D},
      {"flush_packets", "enable flushing of the I/O context after each packet", OFFSET(flush_packets), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, E},
      {"metadata_header_padding", "set number of bytes to be written as padding in a metadata header", OFFSET(metadata_header_padding), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, E},
      {"output_ts_offset", "set output timestamp offset", OFFSET(output_ts_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E},
      {"max_interleave_delta", "maximum buffering duration for interleaving", OFFSET(max_interleave_delta), AV_OPT_TYPE_INT64, { .i64 = 10000000 }, 0, INT64_MAX, E },
      {"f_strict", "how strictly to follow the standards (deprecated; use strict, save via avconv)", OFFSET(strict_std_compliance), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "strict"},
      {"strict", "how strictly to follow the standards", OFFSET(strict_std_compliance), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "strict"},
      {"very", "strictly conform to a older more strict version of the spec or reference software", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_VERY_STRICT }, INT_MIN, INT_MAX, D|E, "strict"},
      {"strict", "strictly conform to all the things in the spec no matter what the consequences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_STRICT }, INT_MIN, INT_MAX, D|E, "strict"},
      {"normal", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_NORMAL }, INT_MIN, INT_MAX, D|E, "strict"},
      {"unofficial", "allow unofficial extensions", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_UNOFFICIAL }, INT_MIN, INT_MAX, D|E, "strict"},
      {"experimental", "allow non-standardized experimental variants", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_EXPERIMENTAL }, INT_MIN, INT_MAX, D|E, "strict"},
      {"max_ts_probe", "maximum number of packets to read while waiting for the first timestamp", OFFSET(max_ts_probe), AV_OPT_TYPE_INT, { .i64 = 50 }, 0, INT_MAX, D },
      {"avoid_negative_ts", "shift timestamps so they start at 0", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, E, "avoid_negative_ts"},
      {"auto",              "enabled when required by target format",    0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_AUTO },              INT_MIN, INT_MAX, E, "avoid_negative_ts"},
      {"disabled",          "do not change timestamps",                  0, AV_OPT_TYPE_CONST, {.i64 = 0 },                                    INT_MIN, INT_MAX, E, "avoid_negative_ts"},
      {"make_non_negative", "shift timestamps so they are non negative", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE }, INT_MIN, INT_MAX, E, "avoid_negative_ts"},
      {"make_zero",         "shift timestamps so they start at 0",       0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_MAKE_ZERO },         INT_MIN, INT_MAX, E, "avoid_negative_ts"},
      {"dump_separator", "set information dump field separator", OFFSET(dump_separator), AV_OPT_TYPE_STRING, {.str = ", "}, 0, 0, D|E},
      {"codec_whitelist", "List of decoders that are allowed to be used", OFFSET(codec_whitelist), AV_OPT_TYPE_STRING, { .str = NULL },  0, 0, D },
      {"format_whitelist", "List of demuxers that are allowed to be used", OFFSET(format_whitelist), AV_OPT_TYPE_STRING, { .str = NULL },  0, 0, D },
      {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL },  0, 0, D },
      {"protocol_blacklist", "List of protocols that are not allowed to be used", OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = NULL },  0, 0, D },
      {"max_streams", "maximum number of streams", OFFSET(max_streams), AV_OPT_TYPE_INT, { .i64 = 1000 }, 0, INT_MAX, D },
      {"skip_estimate_duration_from_pts", "skip duration calculation in estimate_timings_from_pts", OFFSET(skip_estimate_duration_from_pts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, D},
      {"max_probe_packets", "Maximum number of packets to probe a codec", OFFSET(max_probe_packets), AV_OPT_TYPE_INT, { .i64 = 2500 }, 0, INT_MAX, D },
      {NULL},
      };
      

      可以看到,这里大量的初始化代码。

    其它Context 也是类似的,例如 AVCodecContext 也是类型的,这里不再一一概述。

    相关文章

      网友评论

          本文标题:ffmpeg结构体解析-AVClass 和 AVOption

          本文链接:https://www.haomeiwen.com/subject/daclnktx.html