FFmpeg中AVDictionary介绍

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fengbingchun/article/details/94342306

FFmpeg中的AVDictionary是一个结构体,简单的key/value存储,经常使用AVDictionary设置或读取内部参数,声明如下,具体实现在libavutil模块中的dict.c/h,提供此结构体是为了与libav兼容,但它实现效率低下,在FFmpeg 4.1.3版本中已弃用(deprecated),推荐使用libavutil模块中的tree.c/h来替代,但是在一些代码中或API中还是会使用到AVDictionary,包括FFmpeg中的examples,因此这里整理介绍下AVDictionary用法。

typedef struct AVDictionaryEntry {
	char *key;
	char *value;
} AVDictionaryEntry;

struct AVDictionary {
	int count;
	AVDictionaryEntry *elems;
};

1. 一个空字典:AVDictionary* dict = nullptr;

2. 由指定的key获取一个字典条目(dictionary entry):av_dict_get

3. 获取字典条目数:av_dict_count

4. 设置一个字典条目,value为const char*:av_dict_set

5. 设置一个字典条目,value为int:av_dict_set_init,此函数内部会将int转为char*,然后再调用av_dict_set

6. 解析key/value对列表,并将解析的条目添加到字典中:av_dict_parse_string

7. 将条目从一个字典拷贝到另一个字典:av_dict_copy

8. 释放为AVDictonary结构分配的内存以及所有的key/value:av_dict_free

9. 以字符串形式获取一个字典条目:av_dict_get_string

10. av_dict_*中有些接口的最后一个参数为int flags,此参数可接受的有效值为在dict.h文件中定义的宏:

(1). AV_DICT_MATCH_CASE:设置字典中检索的key区分大小写,默认不区分大小写

(2). AV_DICT_IGNORE_SUFFIX:忽略字典中指定条目key的后缀

(3). AV_DICT_DONT_STRDUP_KEY:若key已分配,则不进行复制

(4). AV_DICT_DONT_STRDUP_VAL:若value已分配,则不进行复制

(5). AV_DICT_DONT_OVERWRITE:若指定key在字典中已存在,则不进行覆盖

(6). AV_DICT_APPEND:若指定key在字典中已存在,则value直接拼接到已存在value值的后面

(7). AV_DICT_MULTIKE:允许在字典中存储多个相同的key

FFmpeg中有些API都是通过AVDictionary来设置/读取内部参数的,如avformat_open_input,可设置video size、input format等,其使用可参见https://blog.csdn.net/fengbingchun/article/details/93975844  

libavformat模块的options_table.h文件中列出了AVFormatContext支持的options选项;libavcodec模块的options_table.h文件中列出了AVCodecContext支持的options选项。

注:有时设置的参数会无效

测试代码如下(test_ffmpeg_libavutil.cpp):

#include "funset.hpp"
#include <string.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>

#ifdef __cplusplus
extern "C" {
#endif

#include <libavutil/dict.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>

#ifdef __cplusplus
}
#endif

int test_ffmpeg_libavutil_avdictionary()
{
{
	AVFormatContext* format_ctx = avformat_alloc_context();
	const char* url = "rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov";
	int ret = -1;
	AVDictionary* dict = nullptr;
	av_dict_set(&dict, "max_delay", "100", 0);
	ret = avformat_open_input(&format_ctx, url, nullptr, &dict);
	if (ret != 0) {
		fprintf(stderr, "fail to open url: %s, return value: %d\n", url, ret);
		return -1;
	}

	fprintf(stdout, "dictionary count: %d\n", av_dict_count(format_ctx->metadata));
	AVDictionaryEntry* entry = nullptr;
	while ((entry = av_dict_get(format_ctx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) {
		fprintf(stdout, "key: %s, value: %s\n", entry->key, entry->value);
	}

	avformat_free_context(format_ctx);
	av_dict_free(&dict);
}

{ // reference: https://ffmpeg.org/doxygen/4.1/group__lavu__dict.html
	AVDictionary* d = nullptr; // "create" an empty dictionary
	AVDictionaryEntry* t = nullptr;
	av_dict_set(&d, "foo", "bar", 0); // add an entry
	char* k = av_strdup("key"); // if your strings are already allocated, you can avoid copying them like this
	char* v = av_strdup("value");
	av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
	fprintf(stdout, "dictionary count: %d\n", av_dict_count(d));
	while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) {
		fprintf(stdout, "key: %s, value: %s\n", t->key, t->value); // iterate over all entries in d
	}
	av_dict_free(&d);
}

{
	avdevice_register_all();

	AVDictionary* options = nullptr;
#ifdef _MSC_VER
	const char* input_format_name = "vfwcap";
	const char* url = "";
#else
	const char* input_format_name = "video4linux2";
	const char* url = "/dev/video0";
	av_dict_set(&options, "video_size", "640x480", 0);
	av_dict_set(&options, "input_format", "mjpeg", 0);
#endif

	AVInputFormat* input_fmt = av_find_input_format(input_format_name);
	AVFormatContext* format_ctx = avformat_alloc_context();

	int ret = avformat_open_input(&format_ctx, url, input_fmt, &options);
	if (ret != 0) {
		fprintf(stderr, "fail to open url: %s, return value: %d\n", url, ret);
		return -1;
	}

	fprintf(stdout, "dictionary count: %d\n", av_dict_count(format_ctx->metadata));
	AVDictionaryEntry* entry = nullptr;
	while ((entry = av_dict_get(format_ctx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) {
		fprintf(stdout, "key: %s, value: %s\n", entry->key, entry->value);
	}

	av_dict_free(&options);
	avformat_close_input(&format_ctx);
}

	return 0;
}

执行结果如下:

GitHubhttps://github.com//fengbingchun/OpenCV_Test

展开阅读全文

没有更多推荐了,返回首页