dict.c 源码分析

ffmpeg dict 相关的函数

总结

  1. ffmpeg 的 dict 数据结构本质 动态数组(长度+起始地址) + key-value
  2. 函数
    1. av_dict_get: 遍历所有字典获取
    2. av_dict_set: 字典 elems 最后一个位置添加/更新的 pair,flags 控制各种策略
    3. av_dict_set_int: int 转 string,然后调 av_dict_set
    4. av_dict_iterate: elems 首地址+元素索引来获取 next 应该遍历的元素
    5. av_dict_parse_string: 通过两个分隔符,来获取 key-value,然后 av_dict_set 赋值
    6. av_dict_get_string: av_dict_iterate 遍历所有 pair,然后拼接分隔符
    7. av_dict_copy: av_dict_iterate 遍历 src 元素,然后 av_dict_set 赋值给 dst
    8. av_dict_free: 遍历所有 key-value,释放 pair、elems、AVDictionary
    9. av_dict_count: 返回 AVDictionary->count

数据结构

  • AVDictionary 数据结构,存储字典
struct AVDictionary {
    int count;	//当前 AVDictionary 键值对数量
    AVDictionaryEntry *elems; // elems[]数组
};
typedef struct AVDictionaryEntry {
    char *key;
    char *value;
} AVDictionaryEntry;
  • Dict 匹配模式宏定义
/**< 仅获取键名完全匹配(区分大小写)的条目。仅在 av_dict_get() 中有意义。 */
#define AV_DICT_MATCH_CASE      1
/**< 返回字典中第一个与搜索键前缀匹配的条目,忽略找到的键字符串的后缀部分。仅在 av_dict_get() 中有意义。 */
#define AV_DICT_IGNORE_SUFFIX   2  
/**< 接管键的所有权,该键已通过 av_malloc(),或其他内存分配函数分配。避免重新复制字符串。 */                                         
#define AV_DICT_DONT_STRDUP_KEY 4 
 /**< 接管值的所有权,该值已通过 av_malloc(),或其他内存分配函数分配。避免重新复制字符串。 */
#define AV_DICT_DONT_STRDUP_VAL 8  
/**< 不覆盖已存在的条目。如果键已存在,则保持原值不变。 */
#define AV_DICT_DONT_OVERWRITE 16   
/**< 如果条目已存在,则将新值附加到旧值后面。注意:不会添加任何分隔符,字符串会直接连接在一起。 */
#define AV_DICT_APPEND         32   
/**< 允许在字典中存储多个相同键名的条目。正常情况下相同键会覆盖或附加。 */                                         
#define AV_DICT_MULTIKEY       64   

函数

av_dict_get 获取 key 的 value

AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
                               const AVDictionaryEntry *prev, int flags)
//eg 找字典 key
av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)
  • 通过 av_dict_iterate 遍历所有字典
  • flags 决定如何匹配 key 和字典元素(全匹配、忽略大小写-全转大写、匹配前缀)

av_dict_iterate 迭代字典 next 元素

const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m,
                                         const AVDictionaryEntry *prev)
//eg 用于遍历 AVDictionary 元素
while(t = av_dict_iterate(b,t))
  • 核心 **<font style="color:#DF2A3F;">return</font>**** ****<font style="color:#DF2A3F;">AVDictionary->elems[ prev - AVDictionary->elems + 1 ]</font>**
  • prev 地址是传入的迭代到的地址,即上一个地址(prev == NULL 即是返回第一个元素)
  • AVDictionary->elems 是字典首地址
  • prev - AVDiconary-> elems 表示之前遍历的元素索引,+1 表示 next 元素索引

av_dict_set 赋值 key 的 value

int av_dict_set(AVDictionary **pm, const char *key, const char *value,int flags)

//eg 字典赋值 string 类型 type
av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE)
  • **<font style="color:#DF2A3F;">*pm == NULL</font>** 空字典
    • 调用 av_malloc(底层 malloc / posix_memalign / memalign 等分配,根据指令集)分配内存
  • **<font style="color:#DF2A3F;">flag != AV_DICT_DONT_STRDUP_KEY/VAL</font>** 已给 key/value 分配内存,避免重新分配
    • av_strdup 重新分配 key/value,不然直接类型转换使用原始 key/value
  • **插入新 key **
    • av_realloc_array **扩容 +1 elems 数组,存在最后一个位置**
  • **<font style="color:#DF2A3F;">flag != AV_DICT_MULTIKEY</font>** 不允许多 key
    • av_dict_get 获取是否已有键
  • 字典已有 key
    • **<font style="color:#DF2A3F;">flag == AV_DICT_DONT_OVERWRITE</font>** ,已有 key,跳过
    • **<font style="color:#DF2A3F;">flag == AV_DICT_APPEND</font>** 原值后拼接新值,需重新给 value 分配内存,然后删除 key_old,最后在 elems 最后一个位置插入 key-value
    • 否则覆盖旧值,并将当前元素删除,然后再**最后一个位置插入 key-value**
  • 若字典中无元素,释放整个字典结构

av_dict_set_int 赋值 int 类型 value

int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)

//eg 字典赋值 int 类型 value
av_dict_set(&format_opts, "scan_all_pmts", 1 , AV_DICT_DONT_OVERWRITE)
  • 把输入 int 类型的 value,*转换为 char ,然后调用 av_dict_set 进行赋值
  • 要把 flag 的 AV_DICT_DONT_STRDUP_VAL 清除,因为需要重新分配字符串内存

av_dict_parse_string 解析多个 key-value 对

int av_dict_parse_string(AVDictionary **pm, const char *str,
                         const char *key_val_sep, const char *pairs_sep, int flags)
//eg 解析多个 string 类型字典,: 分割多个 key-val对,= 分割 key 和 val
av_dict_parse_string(&dict, "codec=h264:bitrate=1000000", ":", "=", 0);
  • flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL) 要求复制字符串
  • 通过 parse_key_value_pair 去遍历每一个 pair
    • av_get_token 提取 key 和 value (通过遍历找到 : 和 = 这两个分隔符)
    • av_dict_set 赋值 key-value

av_dict_get_string 返回字典所有 key-vale

int av_dict_get_string(const AVDictionary *m, char **buffer,
                       const char key_val_sep, const char pairs_sep)
//eg str 获取形如 "key1=value1:key2=value2" 的字典
av_dict_get_string(dict, &str, '=', ':');

av_dict_copy 复制字典

int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)

//eg 将 src 中所有键值对深拷贝到 dst 中
av_dict_copy(&dst, src, 0);
  • 底层 **<font style="color:#DF2A3F;">av_dict_iterate + av_dict_set</font>**
  • **<font style="color:#DF2A3F;">flags & AV_DICT_DONT_STRDUP_KEY / VAL</font>** 可以控制深拷贝和浅拷贝****(浅拷贝需要自己承担悬空指针的风险)

av_dict_free 释放字典

void av_dict_free(AVDictionary **pm)

//eg 释放字典
av_dict_free(&dict)
  • 倒序遍历 AVDictionary->elems
  • av_freep 释放每一个 key 和 value
  • av_freep 释放 elems 本身空间
  • av_freep 最后释放 AVDictionary 字典

av_dict_count 返回字典元素数量

int av_dict_count(const AVDictionary *m)

//eg 获取字典元素量
av_dict_count(dict)
  • 本质就是**<font style="color:#DF2A3F;">return AVDictionary->count </font>**

avpriv_dict_set_timestamp 设置字典中时间戳

int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp)

//eg 将当前系统时间(微秒)写入字典中,
//key 为 "creation_time",格式为 ISO 8601(如 2025-05-09T13:45:00Z)。
avpriv_dict_set_timestamp(&dict, "creation_time", av_gettime());
  • 传入 int 时间戳,然后转成 iso 格式字符串,微秒级别
  • av_dict_set 写入 key-value
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值