[时间: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]置位'\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;

支持宏如下:

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\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的实现细节。

参考ffmpeg-doxygen

FFmpeg libavutil主要功能概述的更多相关文章

  1. Power BI官方视频(1) Power BI Desktop 7月份更新功能概述

    2016年7月,Power BI Desktop进行了一些功能更新,提高整体的用户体验.同时也有一些新的和令人兴奋的功能.看看大概介绍,更新功能要点: 本文原文地址:Power BI官方视频(1) P ...

  2. osgearth各个例子功能概述

    osgearth各个例子功能概述 转自:http://blog.csdn.net/wl198302/article/details/21177309 最近在学习osgearth,对其还不是很理解,有些 ...

  3. SAP Business One SAP B1功能概述

    SAP Business One SAP B1功能概述 SAP B One配有易于使用的软件界面,是一款全面的,多功能的业务管理解决方案,贵企业可以将其用作主要的企业资源(ERP)应用程序. 该解决方 ...

  4. Android(java)学习笔记102:Map集合功能概述

    下面通过代码引入Map集合:如下 package cn.itcast_01; import java.util.HashMap; import java.util.Map; /* * 作为学生来说,是 ...

  5. Java基础知识强化之集合框架笔记51:Map集合之Map集合的功能概述与测试

    1. Map集合的功能概述 (1)添加功能 V put(K key,V value):添加元素.这个其实还有另一个功能?先不告诉你,等会讲 如果键是第一次存储,就直接存储元素,返回null 如果键不是 ...

  6. Java基础知识强化之集合框架笔记16:List集合的特有功能概述和测试

    1. List集合的特有功能概述: (1)添加功能: void add(int index, Object element):在指定位置添加元素 (2)获取功能: Object get(int ind ...

  7. Java基础知识强化之集合框架笔记03:Collection集合的功能概述

    1. Collection功能概述:Collection是集合的顶层接口,它子体系有重复的,有唯一性,有有序的,无序的. (1)添加功能 boolean add(Object obj):添加一个元素 ...

  8. ABBYY PDF Transformer+功能概述

    ABBYY PDF Transformer+是一个新的.全面的巧妙解决PDF文档的工具,它将泰比的光学字符识别(OCR)技术和Adobe®PDF技术完美结合,以确保实现便捷地处理任何类型的PDF文件, ...

  9. MicroRNA in Control of Gene Expression: An Overview of Nuclear Functions 微RNA控制基因表达:核功能概述

    MicroRNA in Control of Gene Expression:An Overview of Nuclear Functions微RNA控制基因表达:核功能概述 抽象:小的非编码RNA( ...

随机推荐

  1. 146. 大小写转换 II

    146. Lowercase to Uppercase II Description Implement an upper method to convert all characters in a ...

  2. BZOJ.3218.a + b Problem(最小割ISAP 可持久化线段树优化建图)

    BZOJ UOJ 首先不考虑奇怪方格的限制,就是类似最大权闭合子图一样建图. 对于奇怪方格的影响,显然可以建一条边\((i\to x,p_i)\),然后由\(x\)向\(1\sim i-1\)中权值在 ...

  3. 英语口语练习系列-C30-生日-年历的周日和月份-如果白昼落进

    词汇-生日-birthday 生日庆祝 birthday celebration birth noun UK /bɜːθ/ US /bɝːθ/ the time when a baby or youn ...

  4. Navicat操作数据库时一直显示加载中

    用Navicat for mysql操作mysql数据库,其中一个表怎么也打不开,一直加载,还不能关闭.从网上搜索原因,主要是以下几个原因:原因一:表死锁,会出现这样的情况,锁不释放,无论多久都读取不 ...

  5. js实现一个一个打印字体的功能

    var str = "ddll台湾八百壮士抗议苹果正式发邀请函西安铁警查倒票案自制航模逼停高铁林志玲遭老总熊抱拖拽游艇事故通报大马外交官被暗杀鹿晗又和邮筒合影奥迪男辱骂环卫工 " ...

  6. ubuntu下用nvm配置好nodejs环境

    cd ~mkdir .gitcd .gitgit clone https://github.com/creationix/nvm.git 这样先把nvm下载过来,然后安装 ./install.sh c ...

  7. Mybatis Hibernate->MyBatis

    Hibernate对JDBC的封装程度比较高,不需要编写SQL(Structured Query Language)语句,只要使用HQL(Hibernate Query Language)语言就可以了 ...

  8. R图表入门

    R图表入门 R语言最强的功能就是统计和作图了,在学习了基本语法之后,博主马上体验了一下R的图表功能 条形图 例1 H = c(7,12,28,3,41) M = c("Mar",& ...

  9. hnctf安恒--蜘蛛侠呀

    这题不会做,赛场被吊打,事后才明白 首先解压看到是流量包,放在wireshark,过滤http很明显看到no_flag.zip,当时想这是个关键点,然后把时间都浪费在这上了,赛后发现并没有传输数据的包 ...

  10. HBase 查询导致RegionServer OOM故障复盘

    背景:我司作为某运营商公司的技术咨询公司,发现有第三方开发公司在使用HBase 1.1.2 (HDP 2.4.2.258版本)一段时间使用正常后,从某一天开始报OOM,从而导致RegionServer ...