• FFmpeg libavutil主要功能概述


    [时间:2017-08] [状态:Open]
    [关键词:ffmpeg,avutil,avrational,avlog,avbuffer,avoptoin]

    0 引言

    FFmpeg使用很久了,一直没有认真看过FFmpeg内部源码所提供的各种机制和功能。本文的主要目标是能够初步总结FFmpeg的avutil中所提供的功能。
    FFmpeg官网的文档-libavutil来看,avutil主要有一下几种功能(顺序做了重排):

    1. 数学函数
    2. 字符串操作
    3. 内存管理相关
    4. 数据结构相关
    5. 错误码及错误处理
    6. 日志输出
    7. 其他辅助信息,比如密钥、哈希值、宏、库版本、常量等

    本文将逐个介绍比较avutil所提供的比较常用的函数。
    注意本文编写时ffmpeg版本为3.3

    1 数学函数

    顾名思义,这部分主要提供与基本数学概念相关的功能,方便数学调用及处理。

    有理数的定义如下

    struct AVRational{
        int num; ///< Numerator 分子
        int den; ///< Denominator 分母
    };
    

    近似取值的枚举值enum AVRounding

    enumerator value description
    AV_ROUND_ZERO 0 向零取整
    AV_ROUND_INF 1 向非零取整
    AV_ROUND_DOWN 2 向负无穷取整
    AV_ROUND_UP 3 向正无穷取整
    AV_ROUND_NEAR_INF 5 向无穷取整,包含中点位置
    AV_ROUND_PASS_MINMAX 8192 透传INT64_MIN/MAX,避免出现AV_NOPTS_VALUE

    其他数学函数如下:

    // 获得a和b的最大公约数
    int64_t av_gcd (int64_t a, int64_t b);
    
    // a * b / c,按照rnd标志取整
    int64_t av_rescale (int64_t a, int64_t b, int64_t c); 
    int64_t av_rescale_rnd (int64_t a, int64_t b, int64_t c, enum AVRounding rnd);
    
    // a * bq / cq, 涉及有理数,按照rnd标志取整 
    int64_t av_rescale_q (int64_t a, AVRational bq, AVRational cq); 
    int64_t av_rescale_q_rnd (int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd);
    
    // 比较ts_a/tb_a与ts_b/tb_b的大小,-1:前者小,0:相等,1:后者小 
    int av_compare_ts (int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b);
    
    // 比较余数大小,即a%mod与b%mod,mod必须是2的倍数。
    int64_t av_compare_mod (uint64_t a, uint64_t b, uint64_t mod)
    
    
    // 创建AVRational
    static AVRational av_make_q (int num, int den);
    
    // 比较两个AVRational,0:a==b, 1: a > b, -1: a < b
    static int 	av_cmp_q (AVRational a, AVRational b);
    
    // 将AVRational转化为double
    static double av_q2d (AVRational a);
    
    // 分数的约分,分子分母需要小于max
    int av_reduce (int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
    
    // 分数相乘,return b*c 
    AVRational av_mul_q (AVRational b, AVRational c) av_const
    
    // 分数相除,return b/c
    AVRational av_div_q (AVRational b, AVRational c) av_const
    
    // 分数相加,return b + c
    AVRational av_add_q (AVRational b, AVRational c) av_const
    
    // 分数相减,return b - c 
    AVRational av_sub_q (AVRational b, AVRational c) av_const
    
    // 求倒数,return 1/q 
    static AVRational av_inv_q (AVRational q)
    
    // 浮点转AVRational,分子、分母必须的最大值是max
    AVRational av_d2q (double d, int max) av_const
    
    // 找到离q最近的值,0:等距离,-1:q1离q近,1:q2离q近
    int av_nearer_q (AVRational q, AVRational q1, AVRational q2)
    
    // 找到指定数组中离q最近的值的索引
    int av_find_nearest_q_idx (AVRational q, const AVRational *q_list)
    
    // AVRational转float,返回以32位表示的浮点数(float)值 
    uint32_t av_q2intfloat (AVRational q)
    
    
    // 在特定时间戳上累加一个值,返回为:ts + inc / inc_tb * ts_tb
    int64_t av_add_stable (AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc)
    

    2 字符串操作

    字符串相关函数主要涉及在代码中的字符串操作逻辑。
    其中定义了如下宏:

    // 转译所有空格,包括位于字符串中间的空格
    #define 	AV_ESCAPE_FLAG_WHITESPACE   (1 << 0)
    // 仅对特殊标记字符转译。如果没有该标志,将对av_get_token()返回的特殊字符做转译
    #define 	AV_ESCAPE_FLAG_STRICT   (1 << 1)
    
    // 支持大于0x10FFFF的codepoints
    #define 	AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES   1
    // 支持非字符(0xFFFE和0xFFFF) 
    #define 	AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS   2
    // 支持UTF-16的surrogates codes 
    #define 	AV_UTF8_FLAG_ACCEPT_SURROGATES   4
    // 排除不被XML支持的控制码
    #define 	AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES   8
    
    #define 	AV_UTF8_FLAG_ACCEPT_ALL   AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES
    

    定义的宏有:

    Enumerator value description
    AV_ESCAPE_MODE_AUTO 0 使用自动选择的反转移模式
    AV_ESCAPE_MODE_BACKSLASH 1 使用反斜杠转译
    AV_ESCAPE_MODE_QUOTE 2 使用单引号转译

    支持的接口如下:

    // 查找匹配子字符串,如果找到,返回非0,否则返回0
    // 如果pfx是str的子串,ptr将返回第一匹配字符串的地址
    int av_strstart (const char *str, const char *pfx, const char **ptr);
    // 忽略大小写字母的字符串匹配
    int av_stristart (const char *str, const char *pfx, const char **ptr);
    
    // 标准库中strstr的替代版本,区分大小写字母的字符串匹配
    char * av_stristr (const char *haystack, const char *needle);
    // 标准库中strstr的替代版本,限制字符串长度
    char * av_strnstr (const char *haystack, const char *needle, size_t hay_length);
    
    // 与BSD strlcpy功能类似,复制最多size-1个字符,并将dst[size-1]置位''
    size_t av_strlcpy (char *dst, const char *src, size_t size);
    // 字符串拼接,该保证dst的总长度不超过size-1
    size_t av_strlcat (char *dst, const char *src, size_t size);
    // 字符串格式化输出
    size_t av_strlcatf (char *dst, size_t size, const char *fmt,...);
    
    // 返回从字符串开始位置连续的非''字符的数目
    size_t av_strnlen (const char *s, size_t len);
    
    // 将字符串和参数格式化输出到一个临时缓冲区,正常返回的指针需要通过调用av_free释放
    char * av_asprintf (const char *fmt,...)
    
    // 将double转化为字符串
    char * av_d2str (double d);
    
    // 字符串分割
    char * av_get_token (const char **buf, const char *term);
    // 类似POSIX.1中的strtok_r()函数
    char * av_strtok (char *s, const char *delim, char **saveptr);
    
    // 判断字符类型和转化
    int av_isdigit (int c); // ASCII isdigit
    int av_isgraph (int c); // ASCII isgraph
    int av_isspace (int c); // ASCII isspace
    int av_toupper (int c); // ASCII字符转大写
    int av_tolower (int c); // ASCII字符转小写
    int av_isxdigit (int c); // ASCII isxdigit
    
    // ASCII字符串比较,大小写敏感 
    int av_strcasecmp (const char *a, const char *b);
    // ASCII字符串比较,大小写不敏感
    int av_strncasecmp (const char *a, const char *b, size_t n);
    
    // 查找盘符或根目录
    const char * av_basename (const char *path);
    
    // 获得目录名,此函数会修改path变量的值
    const char * av_dirname (char *path);
    
    // 在names中查找name,找到返回1;否则,返回0
    int av_match_name (const char *name, const char *names);
    // 路径拼接,添加新的folder
    char * av_append_path_component (const char *path, const char *component);
    
    // 文本转译处理
    int av_escape (char **dst, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags);
    
    // UTF-8字符读取
    int av_utf8_decode (int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, unsigned int flags);
    
    // 在list查找name
    int av_match_list (const char *name, const char *list, char separator);
    

    3. 内存管理相关

    内存管理相关函数主要涉及堆管理。其中堆函数包括:

    // 分配指定大小的内存,功能类似c的malloc
    void * av_malloc (size_t size);
    // 分配内存并将该内存初始化为0
    void * av_mallocz (size_t size);
    
    // 作为c中calloc的替代
    void * av_calloc (size_t nmemb, size_t size);
    // 作为c中realloc的替代
    void * av_realloc (void *ptr, size_t size);
    
    // 在buffer不足的情况下,重新分配内存,否则不做处理
    void * av_fast_realloc (void *ptr, unsigned int *size, size_t min_size);
    // 在buffer不够是重新分配,够用时直接使用默认的。
    void av_fast_malloc (void *ptr, unsigned int *size, size_t min_size);
    // av_fast_malloc功能类似,只是分配成功之后初始化为0
    void av_fast_mallocz (void *ptr, unsigned int *size, size_t min_size);
    
    // 释放内存,类似c中的free
    void av_free (void *ptr);
    // 释放内存,并将指针置为空
    void av_freep (void *ptr);
    
    // 字符串复制,并返回一个内存指针,返回值需要通过av_free释放
    char * av_strdup (const char *s);
    char * av_strndup (const char *s, size_t len);
    
    // 内存区域复制,并返回一个动态申请的内存 
    void * av_memdup (const void *p, size_t size);
    
    // 支持重叠区域的memcpy实现
    void av_memcpy_backptr (uint8_t *dst, int back, int cnt);
    
    // 检查a*b是否存在溢出,返回值0表示成功, AVERROR(EINVAL)表示存在溢出
    int av_size_mult (size_t a, size_t b, size_t *r);
    

    4. 数据结构相关

    avutil中的数据结构包括:

    AVBuffer

    AVBuffer是一系列支持引用计数的数据缓冲的API集合。
    其中定义了如下结构体

    // 基于引用计数的buffer类型,外部不可见,通过AVBufferRef访问
    typedef struct AVBuffer AVBuffer;
    
    // 对数据buffer的引用,该结构不应该被直接分配
    struct AVBufferRef {
        AVBuffer *buffer;
    
        uint8_t *data; // 数据缓冲和长度
        int      size;
    };
    

    提供了以下函数:

    // 创建指定长度为size的buffer,一般调用av_malloc
    AVBufferRef * av_buffer_alloc (int size);
    AVBufferRef * av_buffer_allocz (int size);
    // 使用data中长度为size的数据创建AVBuffer,并注册释放函数及标志
    AVBufferRef * av_buffer_create (uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags);
    
    // 使用默认方式释放buffer
    void av_buffer_default_free (void *opaque, uint8_t *data);
    // 复制和减少对buffer的引用计数 
    AVBufferRef * av_buffer_ref (AVBufferRef *buf);
    void av_buffer_unref (AVBufferRef **buf);
    
    // buffer是否可写
    int av_buffer_is_writable (const AVBufferRef *buf);
    
    // 返回av_buffer_create设置的opaque参数 
    void * av_buffer_get_opaque (const AVBufferRef *buf);
    // 返回当前buffer的引用计数值
    int av_buffer_get_ref_count (const AVBufferRef *buf);
     
    // 创建一个可写的buffer
    int av_buffer_make_writable (AVBufferRef **buf);
    // 重新分配buffer大小
    int av_buffer_realloc (AVBufferRef **buf, int size);
    

    AVBufferPool

    AVBufferPool是一个由AVBuffer构成的、没有线程锁的、线程安全的缓冲池。频繁的分配和释放大量内存缓冲区效率可能会较低。AVBufferPool主要解决用户需要使用同样长度的缓冲区的情况(比如,原始音视频帧)。
    在开始用户可以调用av_buffer_pool_init来创建缓冲池。然后在任何时间都可以调用av_buffer_pool_get()来获得buffer,在该buffer的引用计数为0时,将会返回给缓冲池,这样就可以被循环使用了。
    在用户使用完缓冲池之后可以调用av_buffer_pool_uninit()来释放缓冲池。
    其中提供的函数包括:

    // 创建缓冲池
    AVBufferPool * av_buffer_pool_init (int size, AVBufferRef *(*alloc)(int size)); 
    AVBufferPool * av_buffer_pool_init2 (int size, void *opaque, AVBufferRef *(*alloc)(void *opaque, int size), void(*pool_free)(void *opaque));
    
    // 释放缓冲池
    void av_buffer_pool_uninit (AVBufferPool **pool);
    // 获得buffer
    AVBufferRef * av_buffer_pool_get (AVBufferPool *pool);
    

    AVFrame

    AVFrame是对原始多媒体数据的一个基于引用计数的抽象,比较常用的是音频帧和视频帧。这里不给出AVFrame的定义了,有兴趣的可以参考libavutil/frame.h。
    AVFrame必须使用av_frame_alloc()函数进行分配。需要注意的是该函数仅仅常见AVFrame本身,AVFrame中的数据缓冲必须通过其他方式管理。AVFrame必须使用av_frame_free()函数释放。
    AVFrame通常是分配一次,然后用于存放不同的数据,例如AVFrame可以保存从decoder中解码出来的数据。在这种情况下 av_frame_unref()将释放所有由frame添加的引用计数并将其重置为初始值。
    AVFrame中的数据通常基于AVBuffer API提供的引用计数机制。其中的引用计数是保存在AVFrame.buf/AVFrame.extended_buf中的。
    sizeof(AVFrame)并不是公开API的一部分,以保证AVFrame中新添加成员之后可以正常运行。
    AVFrame中的成员可以通过AVOptions访问,使用其对应的名称字符串即可。AVFrame的AVClass可以通过avcodec_get_frame_class()函数获得。
    它提供的主要函数包括:

    // 获取和设置AVFrame.best_effort_timestamp值
    int64_t av_frame_get_best_effort_timestamp (const AVFrame *frame); 
    void av_frame_set_best_effort_timestamp (AVFrame *frame, int64_t val);
    
    // 获取和设置AVFrame.pkt_duration
    int64_t av_frame_get_pkt_duration (const AVFrame *frame); 
    void av_frame_set_pkt_duration (AVFrame *frame, int64_t val);
    
    // 获取和设置AVFrame.pkt_pos
    int64_t av_frame_get_pkt_pos (const AVFrame *frame); 
    void av_frame_set_pkt_pos (AVFrame *frame, int64_t val);
    
    // 获取和设置AVFrame.channel_layout
    int64_t av_frame_get_channel_layout (const AVFrame *frame); 
    void 	av_frame_set_channel_layout (AVFrame *frame, int64_t val);
    
    // 获取和设置AVFrame.channels
    int 	av_frame_get_channels (const AVFrame *frame); 
    void 	av_frame_set_channels (AVFrame *frame, int val);
    
    // 获取和设置AVFrame.sample_rate 
    int 	av_frame_get_sample_rate (const AVFrame *frame); 
    void 	av_frame_set_sample_rate (AVFrame *frame, int val);
    
    // 获取和设置AVFrame.metadata
    AVDictionary * 	av_frame_get_metadata (const AVFrame *frame); 
    void av_frame_set_metadata (AVFrame *frame, AVDictionary *val);
    
    // 获取和设置AVFrame.decode_error_flags
    int av_frame_get_decode_error_flags (const AVFrame *frame); 
    void av_frame_set_decode_error_flags (AVFrame *frame, int val);
    
    // 获取和设置AVFrame.pkt_size 
    int av_frame_get_pkt_size (const AVFrame *frame); 
    void av_frame_set_pkt_size (AVFrame *frame, int val); 
    AVDictionary ** avpriv_frame_get_metadatap (AVFrame *frame)
    
    // 获取和设置AVFrame.colorspace 
    enum AVColorSpace av_frame_get_colorspace (const AVFrame *frame); 
    void av_frame_set_colorspace (AVFrame *frame, enum AVColorSpace val);
    
    // 获取和设置AVFrame.color_range
    enum AVColorRange av_frame_get_color_range (const AVFrame *frame); 
    void av_frame_set_color_range (AVFrame *frame, enum AVColorRange val) 
    
    // 获得ColorSpace的名称
    const char * av_get_colorspace_name (enum AVColorSpace val);
    
    // 创建和释放AVFrame
    AVFrame * av_frame_alloc (void);
    void av_frame_free (AVFrame **frame);
    
    // 增加引用计数
    int av_frame_ref (AVFrame *dst, const AVFrame *src);
    // AVFrame复制
    AVFrame * av_frame_clone (const AVFrame *src);
    // 去除引用计数 
    void av_frame_unref (AVFrame *frame);
    // 引用计数转移
    void av_frame_move_ref (AVFrame *dst, AVFrame *src);
    // 重新分配缓冲区 
    int av_frame_get_buffer (AVFrame *frame, int align);
    // AVFrame复制 
    int av_frame_copy (AVFrame *dst, const AVFrame *src); 
    int av_frame_copy_props (AVFrame *dst, const AVFrame *src);
    
    // 获得某个平面的数据
    AVBufferRef * av_frame_get_plane_buffer (AVFrame *frame, int plane);
    

    AVOptions

    AVOptions提供了通用的option设置和获取机制,可适用于任意struct(通常要求该结构体的第一个成员必须是AVClass指针,该AVClass.options必须指向一个AVOptions的静态数组,以NULL作为结束)。后续会详细介绍其中原理,这里只整理ffmpeg针对AVOptions所提供的函数。
    Option设置函数-set

    int av_opt_set (void *obj, const char *name, const char *val, int search_flags); // 任意字符串
    int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags);  // int
    int av_opt_set_double (void *obj, const char *name, double val, int search_flags); // double
    int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); // AVRational
    int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); // 二进制
    int av_opt_set_image_size (void *obj, const char *name, int w, int h, int search_flags); // 图像分辨率
    int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); // PixelFormat
    int av_opt_set_sample_fmt (void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); // SampleFormat
    int av_opt_set_video_rate (void *obj, const char *name, AVRational val, int search_flags); // 视频帧率
    int av_opt_set_channel_layout (void *obj, const char *name, int64_t ch_layout, int search_flags); // channel_layou
    int av_opt_set_dict_val (void *obj, const char *name, const AVDictionary *val, int search_flags); // AVDictionary
    

    Option获取函数-get

    int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); 
    int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); 
    int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); 
    int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); 
    int av_opt_get_image_size (void *obj, const char *name, int search_flags, int *w_out, int *h_out); 
    int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); 
    int av_opt_get_sample_fmt (void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); 
    int av_opt_get_video_rate (void *obj, const char *name, int search_flags, AVRational *out_val);
    int av_opt_get_channel_layout (void *obj, const char *name, int search_flags, int64_t *ch_layout); 
    int av_opt_get_dict_val (void *obj, const char *name, int search_flags, AVDictionary **out_val);
    

    结构体定义

    struct AVOption {
        const char *name;
        const char *help;
        int offset; // 相对于上下文的偏移量,对常量而言,必须是0
        enum AVOptionType type; // 类型
    
     	// 实际存储数据的共用体
        union {
            int64_t i64;
            double dbl;
            const char *str;
            AVRational q;
        } default_val;
        double min;
        double max;
        int flags; // AV_OPT_FLAG_XXX
        const char *unit; // 
    };
    
    struct AVOptionRange {
        const char *str;
        double value_min, value_max; // 值范围,对字符串表示长度,对分辨率表示最大最小像素点个数
        double component_min, component_max;// 实际数据取值区间,对字符串,表示unicode的取值范围ASCII为[0,127]
        int is_range;// 是否是一个取值范围,1-是,0-单值
    };
    
    struct AVOptionRanges {
        AVOptionRange **range;
        int nb_ranges; // range数目
        int nb_components; // 组件数目
    } AVOptionRanges;
    

    支持的宏和枚举值

    // 优先检索给定对象的子对象
    #define AV_OPT_SEARCH_CHILDREN   (1 << 0) 
    #define AV_OPT_SEARCH_FAKE_OBJ   (1 << 1)
    // 在av_opt_get中支持返回NULL,而不是空字符串 
    #define AV_OPT_ALLOW_NULL   (1 << 2)
    // 支持多组件范围的Option
    #define AV_OPT_MULTI_COMPONENT_RANGE   (1 << 12)
    // 只保存非默认值的Option 
    #define AV_OPT_SERIALIZE_SKIP_DEFAULTS   0x00000001
    // 只保存完全符合opt_flags的option
    #define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT   0x00000002
     
    枚举值
    enum AVOptionType { 
      AV_OPT_TYPE_FLAGS, AV_OPT_TYPE_INT, AV_OPT_TYPE_INT64, AV_OPT_TYPE_DOUBLE, 
      AV_OPT_TYPE_FLOAT, AV_OPT_TYPE_STRING, AV_OPT_TYPE_RATIONAL, AV_OPT_TYPE_BINARY, 
      AV_OPT_TYPE_DICT, AV_OPT_TYPE_UINT64, AV_OPT_TYPE_CONST = 128, AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), 
      AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'),
      AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), 
      AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'),
      AV_OPT_TYPE_BOOL = MKBETAG('B','O','O','L') 
    }
     
    enum  { AV_OPT_FLAG_IMPLICIT_KEY = 1 }
    

    支持的函数如下:

    // 显示obj的所有options
    int av_opt_show2 (void *obj, void *av_log_obj, int req_flags, int rej_flags);
    // 将s的所有options设置为默认值
    void av_opt_set_defaults (void *s);
    void av_opt_set_defaults2 (void *s, int mask, int flags);
    
    // 解析opts中的key/value对,并设置(主要区别是对ctx要求不一样)
    int av_set_options_string (void *ctx, const char *opts, const char *key_val_sep, const char *pairs_sep);
    int av_opt_set_from_string (void *ctx, const char *opts, const char *const *shorthand, const char *key_val_sep, const char *pairs_sep);
    // 释放obj所有分配的options资源
    void av_opt_free (void *obj);
    // 检查obj.flag_name对应的AVOption属性名为filed_name时该值是否设置
    int av_opt_flag_is_set (void *obj, const char *field_name, const char *flag_name);
    // 从AVDictionary读取Option 
    int av_opt_set_dict (void *obj, struct AVDictionary **options);
    int av_opt_set_dict2 (void *obj, struct AVDictionary **options, int search_flags);
    
    // 从ropts开始提取key/value对 
    int av_opt_get_key_value (const char **ropts, const char *key_val_sep, const char *pairs_sep, unsigned flags, char **rkey, char **rval);
    // 在obj中查找名字为name的AVOption
    const AVOption * av_opt_find (void *obj, const char *name, const char *unit, int opt_flags, int search_flags);
    const AVOption * av_opt_find2 (void *obj, const char *name, const char *unit, int opt_flags, int search_flags, void **target_obj);
    
    // 遍历obj中所有AVOption
    const AVOption * av_opt_next (const void *obj, const AVOption *prev);
    // 遍历obj中所有使能的子对象
    void * 	av_opt_child_next (void *obj, void *prev); 
    const AVClass * av_opt_child_class_next (const AVClass *parent, const AVClass *prev);
    
    // 获取obj中名字为name的属性的指针
    void * av_opt_ptr (const AVClass *avclass, void *obj, const char *name);
    
    // AVOption复制
    int av_opt_copy (void *dest, const void *src);
    
    // 释放AVOptionRanges,并置为NULL
    void av_opt_freep_ranges (AVOptionRanges **ranges);
    // 获取有效范围的取值 
    int av_opt_query_ranges (AVOptionRanges **, void *obj, const char *key, int flags);
    int av_opt_query_ranges_default (AVOptionRanges **, void *obj, const char *key, int flags);
     
    // 获取是否所有的AVOption都是默认值
    int av_opt_is_set_to_default (void *obj, const AVOption *o); 
    int av_opt_is_set_to_default_by_name (void *obj, const char *name, int search_flags);
    // 序列化所有的AVOption
    int av_opt_serialize (void *obj, int opt_flags, int flags, char **buffer, const char key_val_sep, const char pairs_sep);
     	Serialize object's options. More...
    

    AVDictionary

    一个简单的键值对的字典集。其中公开的只有以下结构

    typedef struct AVDictionaryEntry {
        char *key;
        char *value;
    } AVDictionaryEntry;
    
    typedef struct AVDictionary AVDictionary;
    

    支持宏如下:

    name value desc
    AV_DICT_MATCH_CASE 1 大小写完全匹配的key检索
    AV_DICT_IGNORE_SUFFIX 2 忽略后缀
    AV_DICT_DONT_STRDUP_KEY 4 不复制key
    AV_DICT_DONT_STRDUP_VAL 8 不复制value
    AV_DICT_DONT_OVERWRITE 16 不要覆盖原有值
    AV_DICT_APPEND 32 如果存在,则添加
    AV_DICT_MULTIKEY 64 支持多重键值

    函数如下:

    // 从prev开始检索m中的键值为key的元素
    AVDictionaryEntry * av_dict_get (const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags);
    // 获得m中元素个数
    int av_dict_count (const AVDictionary *m);
    // 设置*pm中的key:value键值对
    int av_dict_set (AVDictionary **pm, const char *key, const char *value, int flags);
    // 使用int64_t的value类型
    int av_dict_set_int (AVDictionary **pm, const char *key, int64_t value, int flags);
    // 从str中解析键值对,并添加到*pm中
    int av_dict_parse_string (AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags);
    // AVDictionary复制
    int av_dict_copy (AVDictionary **dst, const AVDictionary *src, int flags);
    // 释放AVDictionary
    void av_dict_free (AVDictionary **m);
    // 按照字符串格式输出AVDictionary的所有数据
    int av_dict_get_string (const AVDictionary *m, char **buffer, const char key_val_sep, const char pairs_sep);
    

    AVTree

    低复杂度的树容器。插入、删除、查找等常用操作都是O(log n)复杂度的实现版本。
    提供以下接口:

    // 创建
    struct AVTreeNode * av_tree_node_alloc (void);
    // 元素查找 
    void * av_tree_find (const struct AVTreeNode *root, void *key, int(*cmp)(const void *key, const void *b), void *next[2]);
    // 元素插入
    void * av_tree_insert (struct AVTreeNode **rootp, void *key, int(*cmp)(const void *key, const void *b), struct AVTreeNode **next);
    // 销毁
    void av_tree_destroy (struct AVTreeNode *t);
    // 数元素枚举 
    void av_tree_enumerate (struct AVTreeNode *t, void *opaque, int(*cmp)(void *opaque, void *elem), int(*enu)(void *opaque, void *elem));
    

    5. 错误码及错误处理

    这部分主要提供统一的错误处理逻辑,可以参考下。其中提供机制如下:

    #define AVERROR(e) (e)  // 错误值
    #define AVUNERROR(e) (e) // 非错误值
    #define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) // 生成四字节错误码
    #define AV_ERROR_MAX_STRING_SIZE 64 // 错误字符的最大长度
    // 错误码转字符串,方便使用的宏 
    #define av_err2str(errnum) av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum)
    

    函数包括

    // 根据错误码,将错误信息输出到errbuf中,返回负值表示错误码未找到。
    int av_strerror (int errnum, char *errbuf, size_t errbuf_size);
    // 功能类似,只是返回值不同
    static char * av_make_error_string (char *errbuf, size_t errbuf_size, int errnum);
    

    6. 日志模块

    日志模块主要提供日志输出的相关接口和宏,通过这些接口外部可以完全控制ffmpeg所有的日志输出。
    其中定义的宏如下:

    name value desc
    AV_LOG_QUIET -8 无任何日志输出
    AV_LOG_PANIC 0 发生无法处理的错误,程序将崩溃
    AV_LOG_FATAL 8 发生无法恢复的错误,例如特定格式的文件头没找到
    AV_LOG_ERROR 16 发生错误,无法无损恢复,但是对后续运行无影响
    AV_LOG_WARNING 24 警告信息,有些部分不太正确,可能会也可能不会导致问题
    AV_LOG_INFO 32 标准信息输出,通常可以使用这个
    AV_LOG_VERBOSE 40 详细信息,通常比较多,频繁输出那种
    AV_LOG_DEBUG 48 仅用于libav*开发者使用的标志
    AV_LOG_TRACE 56 特别繁琐的调试信息,仅用在libav*开发中
    // 最大log级别的跨度
    #define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET)
    #define AV_LOG_C(x) ((x) << 8) // 设置日志输出的颜色,通常用法如下:
    av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple
    ");
    // 跳过重复的日志
    #define AV_LOG_SKIP_REPEATED   1
    // 输出日志对应的level
    #define AV_LOG_PRINT_LEVEL   2
    

    支持的函数接口有:

    // 日志输出函数
    void av_log (void *avcl, int level, const char *fmt,...);
    void av_vlog (void *avcl, int level, const char *fmt, va_list vl);
    
    // 设置和获取av_log_level
    int av_log_get_level (void);
    void av_log_set_level (int level);
    
    // 设置日志输出回调函数及默认的日志回调函数
    void av_log_set_callback (void(*callback)(void *, int, const char *, va_list)); 
    void av_log_default_callback (void *avcl, int level, const char *fmt, va_list vl);
    
    // 获得ctx的名字
    const char * av_default_item_name (void *ctx);
    // 获得AVClassCategory分类
    AVClassCategory av_default_get_category (void *ptr)
    
    // 使用ffmpeg默认的log输出方式格式化参数
    void av_log_format_line (void *ptr, int level, const char *fmt, va_list vl, char *line, int line_size, int *print_prefix);
    int av_log_format_line2 (void *ptr, int level, const char *fmt, va_list vl, char *line, int line_size, int *print_prefix);
    
    // 设置日志输出相关的flag
    void av_log_set_flags (int arg); 
    int av_log_get_flags (void);
    

    7. 其他辅助信息

    包括密钥、哈希值、宏、库版本、常量等。
    FFmpeg支持AES、Base64、blowfish等常用的密钥算法,hash函数支持CRC、MD5、SHA、SHA-512等。
    字符串处理宏

    #define AV_STRINGIFY(s) AV_TOSTRING(s) // 转化为字符串
    #define AV_TOSTRING(s) #s 
    #define AV_GLUE(a, b) a ## b // 两个变量拼接
    #define AV_JOIN(a, b) AV_GLUE(a, b)
    

    库版本宏

    // 版本号的两种信息
    #define AV_VERSION_INT(a, b, c)   ((a)<<16 | (b)<<8 | (c))
    #define AV_VERSION_DOT(a, b, c)   a ##.## b ##.## c 
    #define AV_VERSION(a, b, c)   AV_VERSION_DOT(a, b, c)
    // 主版本、次版本、微版本号
    #define AV_VERSION_MAJOR(a) ((a) >> 16) 
    #define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8) 
    #define AV_VERSION_MICRO(a) ((a) & 0xFF)
    
    #define LIBAVUTIL_VERSION_MAJOR   55 
    #define LIBAVUTIL_VERSION_MINOR   74 
    #define LIBAVUTIL_VERSION_MICRO   100
     
    #define LIBAVUTIL_VERSION_INT 
    #define LIBAVUTIL_VERSION
     
    #define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
    

    函数有

    unsigned avutil_version (void);
    const char * av_version_info (void); 
    const char * avutil_configuration (void);// 配置字符串 
    const char * avutil_license (void);
    

    时间戳相关的常量宏

    // 未定义的时间戳
    #define AV_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000))
    // 内部时间基准,通常是us
    #define AV_TIME_BASE   1000000
    #define AV_TIME_BASE_Q   (AVRational){1, AV_TIME_BASE}
    

    同时额外定义了以下结构:

    #define AV_FOURCC_MAX_STRING_SIZE 32 
    #define av_fourcc2str(fourcc) av_fourcc_make_string((char[AV_FOURCC_MAX_STRING_SIZE]){0}, fourcc)
    char * av_fourcc_make_string (char *buf, uint32_t fourcc);// 将fourcc填充到字符串中
    
    enum  	AVMediaType { 
      AVMEDIA_TYPE_UNKNOWN = -1, AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA, 
      AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_ATTACHMENT, AVMEDIA_TYPE_NB 
    }
     
    // 获得AVMediaType对应的字符串
    const char * av_get_media_type_string (enum AVMediaType media_type);
    // 使用utf8的文件名打开文件 
    FILE * av_fopen_utf8 (const char *path, const char *mode);
    // 返回表示内部时间戳的time_base 
    AVRational av_get_time_base_q (void);
    

    最后一部分是关于AVPicture的用法说明,其中包括像素采样格式、基本图像平面操作等。
    枚举量有:

    // 各种帧类型,I/P/B/S/SI/SP/BI
    enum  AVPictureType { 
      AV_PICTURE_TYPE_NONE = 0, AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, 
      AV_PICTURE_TYPE_S, AV_PICTURE_TYPE_SI, AV_PICTURE_TYPE_SP, AV_PICTURE_TYPE_BI 
    }
    

    函数有:

    // 使用单个字符表示图片类型,未知时返回'?'
    char av_get_picture_type_char (enum AVPictureType pict_type);
    
    // 计算给定采样格式和宽度的图像的linesize
    int av_image_get_linesize (enum AVPixelFormat pix_fmt, int width, int plane);
    // 填充特定采样格式和宽度的linesize数组
    int av_image_fill_linesizes (int linesizes[4], enum AVPixelFormat pix_fmt, int width);
    // 使用ptr中的数据填充plane中的数组(不申请内存)
    int av_image_fill_pointers (uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, uint8_t *ptr, const int linesizes[4]);
    // 根据给定的格式分配Image数组,主要是pointers和linesizes 
    int av_image_alloc (uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);
    // 复制特定plane的数据,即将src中数据拷贝到dst中
    void av_image_copy_plane (uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height);
    // 复制Image,将src_data中的数据拷贝到dst_data中
    void av_image_copy (uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height);
    
    // 将src填充到dst_data中 
    int av_image_fill_arrays (uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align);
    // 返回指定格式的图片需要的缓冲区长度
    int av_image_get_buffer_size (enum AVPixelFormat pix_fmt, int width, int height, int align);
    
    // 将图像填充为黑色 
    int av_image_fill_black (uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], enum AVPixelFormat pix_fmt, enum AVColorRange range, int width, int height);
    

    8 结语

    到此,本文简单的整理了下FFmpeg中libavutil所提供的主要函数和常量,仅仅是为了整理了解,如果大家需要查看具体文档,建议使用FFmpeg官网的doxygen生成的标准文档。
    整理本文的目的只是为了加强记忆。后续会介绍下AVOption、AVLog、AVBuffer的实现细节。

    参考ffmpeg-doxygen

  • 相关阅读:
    时间戳与时间之间的相互转化
    源代码管理之Git命令的使用
    ios最新设置状态栏字体颜色总结
    iOS 代码方式设置按钮标题、图片的偏移
    runloop简单介绍
    iOS中的多线程NSThread/GCD/NSOperation & NSOperationQueue
    AFNetworking的详细解析
    MATLAB相关快捷键以及常用函数
    CentOS 5.8下快速搭建FTP服务器
    php获取跳转后的真实链接
  • 原文地址:https://www.cnblogs.com/tocy/p/ffmpeg-libavutil-details.html
Copyright © 2020-2023  润新知