[时间:2017-08] [状态:Open]
[关键词:ffmpeg,avutil,avrational,avlog,avbuffer,avoptoin]
0 引言
FFmpeg使用很久了,一直没有认真看过FFmpeg内部源码所提供的各种机制和功能。本文的主要目标是能够初步总结FFmpeg的avutil中所提供的功能。
从FFmpeg官网的文档-libavutil来看,avutil主要有一下几种功能(顺序做了重排):
- 数学函数
- 字符串操作
- 内存管理相关
- 数据结构相关
- 错误码及错误处理
- 日志输出
- 其他辅助信息,比如密钥、哈希值、宏、库版本、常量等
本文将逐个介绍比较avutil所提供的比较常用的函数。
注意本文编写时ffmpeg版本为3.3
1 数学函数
顾名思义,这部分主要提供与基本数学概念相关的功能,方便数学调用及处理。
有理数的定义如下
struct AVRational{
int num; ///< Numerator 分子
int den; ///< Denominator 分母
};
近似取值的枚举值enum AVRounding
:
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
定义的宏有:
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]置位'\0'
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,...);
// 返回从字符串开始位置连续的非'\0'字符的数目
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;
支持宏如下:
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所有的日志输出。
其中定义的宏如下:
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\n");
// 跳过重复的日志
#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的实现细节。