从代码分析,dict功能实际就是一个查找器,将对象数据字符串"AAAA"映射到标识字符串"BBBB",通过字符串"BBBB"查找到对应映射的字符串"AAAA";
代码设计上比较简单,差不多就是简单的遍历数组。
struct AVDictionary {
int count;
AVDictionaryEntry *elems;
};
int av_dict_count(const AVDictionary *m)
{
return m ? m->count : 0;
}
AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
const AVDictionaryEntry *prev, int flags)
{
unsigned int i, j;
if (!m)
return NULL;
//计算prev对象在字典中的索引
if (prev)
//指定prev, prev对象地址减去首地址 + 1为prev在m->elems中的索引
i = prev - m->elems + 1;
else
//未指定prev,从0开始索引
i = 0;
for (; i < m->count; i++) {
const char *s = m->elems[i].key;
if (flags & AV_DICT_MATCH_CASE)
//区分大小写
for (j = 0; s[j] == key[j] && key[j]; j++)
;
else
//不区分大小写
for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++)
;
if (key[j])//说明匹配不成功
continue;
//如果不忽略后缀,则表示匹配不成功,反之
if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
continue;
//返回索引到的对象
return &m->elems[i];
}
//索引不成功,返回失败
return NULL;
}
int av_dict_set(AVDictionary **pm, const char *key, const char *value,
int flags)
{
AVDictionary *m = *pm;
AVDictionaryEntry *tag = NULL;
char *oldval = NULL, *copy_key = NULL, *copy_value = NULL;
if (!(flags & AV_DICT_MULTIKEY)) {
//如果不允许相同键值被存储,则将键值读出来,后续处理
tag = av_dict_get(m, key, NULL, flags);
}
if (flags & AV_DICT_DONT_STRDUP_KEY)
//如果设置接管键值则
copy_key = (void *)key;
else
//否则
copy_key = av_strdup(key);
if (flags & AV_DICT_DONT_STRDUP_VAL)
//如果设置接管信息,则
copy_value = (void *)value;
else if (copy_key)
copy_value = av_strdup(value);
if (!m)
//字典句柄不存在,申请新空间组织
m = *pm = av_mallocz(sizeof(*m));
if (!m || (key && !copy_key) || (value && !copy_value))
goto err_out;
if (tag) {
//设置了相同键值,但不允许,所以需要处理一下
if (flags & AV_DICT_DONT_OVERWRITE) {
//不允许重写已经存在的键值,返回失败,并释放相关的内存空间
av_free(copy_key);
av_free(copy_value);
return 0;
}
//是否设置追加
if (flags & AV_DICT_APPEND)
//设置允许追加,先保存旧值
oldval = tag->value;
else
//设置不允许追加,释放旧值
av_free(tag->value);
//释放旧键值
av_free(tag->key);
//将最后一个对象拷贝到tag上
*tag = m->elems[--m->count];
} else if (copy_value) {
//设置了新键值,需要对键值对象进行存储空间申请
//(动态数组 ==>
// 在m->elems指针的基础上,新增内存空间,
// 有连续空间则连续申请,无连续空间则重新申请整个
// 需要空间,再把数据拷贝过去,最后释放非连续的原先内存)
AVDictionaryEntry *tmp = av_realloc_array(m->elems,
m->count + 1, sizeof(*m->elems));
if (!tmp)
goto err_out;
m->elems = tmp;
}
if (copy_value) {
//有新对象添加,将新键值/数据存储到字典最后一个对象
m->elems[m->count].key = copy_key;
m->elems[m->count].value = copy_value;
if (oldval && flags & AV_DICT_APPEND) {
//将两个数据内容合并
size_t len = strlen(oldval) + strlen(copy_value) + 1;
char *newval = av_mallocz(len);
if (!newval)
goto err_out;
av_strlcat(newval, oldval, len);
av_freep(&oldval);
av_strlcat(newval, copy_value, len);
m->elems[m->count].value = newval;
av_freep(©_value);
}
m->count++;
} else {
av_freep(©_key);
}
if (!m->count) {
//内部没有对象,销毁整个字典
av_freep(&m->elems);
av_freep(pm);
}
return 0;
err_out:
if (m && !m->count) {
av_freep(&m->elems);
av_freep(pm);
}
av_free(copy_key);
av_free(copy_value);
return AVERROR(ENOMEM);
}
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
int flags)
{
char valuestr[22];
snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
//设置需要拷贝value值
flags &= ~AV_DICT_DONT_STRDUP_VAL;
return av_dict_set(pm, key, valuestr, flags);
}