AVDictionary
首先给出AVDictionary在FFmpeg中的源码实现。
//AVDicttionary源码
struct AVDictionary {
int count; //elems数组中元素的个数
AVDictionaryEntry *elems; //AVDictionaryEntry数组
};
//AVDictionaryEntry源码
typedef struct AVDictionaryEntry {
char *key; //AVDictionaryEntry中将数据按照键值队的方式存储
char *value; //key为键 value为值 存放的均为字符串
} AVDictionaryEntry;
在了解了AVDictionary的源码实现后其实大家就应该了解了其内部机理,其对于函数的实现大家也都能猜测到,下面只给出av_dict_get 以及 av_dict_set的源码实现作为参考
av_dict_get
闲话少说先上源码:
const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
{ //本函数返回prev指针的下一个元素AVDictionaryEntry (相当于return prev->next //伪码)
int i = 0; //存储的是数组地址的差值 用来当作索引 如elems = elems[0], *(elems+i) = elems[i]
if (!m) //AVDictionary *m 不存在就直接返回 没什么好说的
return NULL;
if (prev) //如果prev不为空, 那么将prev指向其下一个元素
i = prev - m->elems + 1; //地址差值
av_assert2(i >= 0); //断言
if (i >= m->count) //容错判断
return NULL;
return &m->elems[i];//如果prev为NULL 那么返回m->elems[0] 否则返回prev的下一个AVDictionaryEntry
}
AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
const AVDictionaryEntry *prev, int flags)
{
const AVDictionaryEntry *entry = prev;
unsigned int j;,
if (!key) //如果要查找的key为空 那么直接返回NULL
return NULL;
while ((entry = av_dict_iterate(m, entry))) { //while内遍历字典(AVDictionary) m, 找对应的key
const char *s = entry->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]) //字符串key未轮询完 则继续
continue;
if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX)) //是否要完全匹配
continue;
return (AVDictionaryEntry *)entry; //返回查找到的AVDictionaryEntry
}
return NULL; //找不到
}
上述代码注意av_dict_iterate即可(对编程初学者来说可能难理解)
av_dict_set
源码如下:
char *av_strdup(const char *s)
{ //创建一片和s同样大小的新的内存,由ptr指向这片内存空间,然后将s中的内容拷贝到ptr
char *ptr = NULL;
if (s) {
size_t len = strlen(s) + 1;
ptr = av_realloc(NULL, len);
if (ptr)
memcpy(ptr, s, len);
}
return ptr;
}
int av_dict_set(AVDictionary **pm, const char *key, const char *value,
int flags)
{
AVDictionary *m = *pm;
AVDictionaryEntry *tag = NULL;
char *copy_key = NULL, *copy_value = NULL;
int err;
if (flags & AV_DICT_DONT_STRDUP_VAL)
copy_value = (void *)value;
else if (value)
copy_value = av_strdup(value);
if (!key) {
err = AVERROR(EINVAL);
goto err_out;
}
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);
//如果传入AVDictionary* pDic = NULL;*pm==m==NULL
//这里判断的是传入的AVDictionary*指针不为空,如果为空 就为其分配如果传入AVDictionary大小的空间
if (!m)
m = *pm = av_mallocz(sizeof(*m));
if (!m || !copy_key || (value && !copy_value))
goto enomem;
//如果存在相同的key
if (tag) {
if (flags & AV_DICT_DONT_OVERWRITE) {//不允许覆盖的情况下 放弃set覆盖
av_free(copy_key);
av_free(copy_value);
return 0;
}
if (copy_value && flags & AV_DICT_APPEND) {//追加的情况下 在旧值后面追加新值
size_t oldlen = strlen(tag->value);
size_t new_part_len = strlen(copy_value);
size_t len = oldlen + new_part_len + 1;
char *newval = av_realloc(tag->value, len);
if (!newval)
goto enomem;
memcpy(newval + oldlen, copy_value, new_part_len + 1);
av_freep(©_value);
copy_value = newval;
} else //在其他情况下 释放旧值 插入新值
av_free(tag->value);
av_free(tag->key);
*tag = m->elems[--m->count];//tag指向末尾
} else if (copy_value) {
AVDictionaryEntry *tmp = av_realloc_array(m->elems,
m->count + 1, sizeof(*m->elems));
if (!tmp)
goto enomem;
m->elems = tmp;
}
if (copy_value) {
m->elems[m->count].key = copy_key;
m->elems[m->count].value = copy_value;
m->count++;
} else {
if (!m->count) {
av_freep(&m->elems);
av_freep(pm);
}
av_freep(©_key);
}
return 0;
enomem:
err = AVERROR(ENOMEM);
err_out:
if (m && !m->count) {
av_freep(&m->elems);
av_freep(pm);
}
av_free(copy_key);
av_free(copy_value);
return err;
}