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]置位'\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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM