[时间: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. 原生JavaScript支持6种方式获取元素

    一.原生JavaScript支持6种方式获取元素 document.getElementById('id'); document.getElementsByName('name'); document ...

  2. react组件通信那些事儿

    父组件是调用组件的组件.现在看来,感觉父组件就是一个壳子,定义好壳子里面会有什么,而子组件是一个具体的实现,说明,会用到什么东西,如果有这些东西,会进行什么操作.总之,父组件是材料,有水和泥,子组件告 ...

  3. BZOJ.1812.[IOI2005]Riv 河流(树形背包)

    BZOJ 洛谷 这个数据范围..考虑暴力一些把各种信息都记下来.不妨直接令\(f[i][j][k][0/1]\)表示当前为点\(i\),离\(i\)最近的建了伐木场的\(i\)的祖先为\(j\),\( ...

  4. RabbitMQ主题模式

    Send类 package topics; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; imp ...

  5. 2190 ACM 数学概率论的乘法和加法原则

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2190 思路:明显我们要寻找 边长为n和边长为n-1,n-2,n-3·····的规律,这样得出一个递推公式就 ...

  6. 潭州课堂25班:Ph201805201 django 项目 第二十五课 文章多级评论前后台实现 (课堂笔记)

    添加新闻评论功能 1.分析 业务处理流程: 判断前端传的新闻id是否为空,是否为整数.是否不存在 判断评论的内容是否为空 判断是否有父评论,父评论的id是否与新闻id匹配 判断用户是否登录 保存新闻评 ...

  7. BZOJ3945 : 无聊的邮递员

    因为两个人方案的对称性,可以将$k$除以$2$,转化为在$n-1$个间隔中设置若干断点,求第$k$小的增量. 对于选中的相邻的断点$(a,a+1)$和$(b,b+1)$,增量为$|x_a-x_{b+1 ...

  8. 3ds max学习笔记(十六)-- 摄像机

    摄像机添加以及应用技巧:可以更改观察的视点和空间广阔,模拟景深和运动模糊效果: 1,添加:更改观察的角度和位置,增加场景透视感: 基本操作: 景深:

  9. Java 使用RMI

    Java 使用RMI Java使用序列化的方式,可以实现远端的方法调用,在分工合作时非常方便.本文记录使用java标准库实现rmi 一.服务端 结构 . ├── pom.xml ├── src │   ...

  10. 小甲鱼Python第八讲课后习题

    0. 下面的循环会打印多少次"I Love FishC"?