1. 函数原型
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags);
2. 参数说明
|
参数 |
类型 |
描述 |
|---|---|---|
|
|
|
指向字典指针的指针 |
|
|
|
要设置的键(字符串) |
|
|
|
要设置的值(字符串),为 NULL 时删除键 |
|
|
|
控制函数行为的标志位 |
3. 返回值
-
成功返回 0
-
失败返回负的错误码
4. 核心功能
4.1 基本用法
#include <libavutil/dict.h>
AVDictionary *dict = NULL;
int ret;
// 1. 添加键值对
ret = av_dict_set(&dict, "name", "value", 0);
if (ret < 0) {
// 错误处理
}
// 2. 修改现有键的值
ret = av_dict_set(&dict, "name", "new_value", 0);
// 3. 删除键(value 为 NULL)
ret = av_dict_set(&dict, "name", NULL, 0);
4.2 标志位详解
4.2.1 键名匹配方式
// 默认:键名不区分大小写
av_dict_set(&dict, "Key", "value1", 0);
av_dict_set(&dict, "key", "value2", 0); // 覆盖上一个
// 区分大小写
av_dict_set(&dict, "Key", "value1", AV_DICT_MATCH_CASE);
av_dict_set(&dict, "key", "value2", AV_DICT_MATCH_CASE); // 添加新条目
4.2.2 内存管理标志
char *key = strdup("custom_key");
char *value = strdup("custom_value");
// 方式1:字典复制字符串(默认行为)
av_dict_set(&dict, "key", "value", 0);
// 字典内部会复制字符串,调用者可以释放自己的字符串
// 方式2:字典接管字符串内存
av_dict_set(&dict, key, value,
AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
// 注意:调用者不能释放 key 和 value 的内存,字典会在释放时统一管理
4.2.3 覆盖控制
// 1. 默认:覆盖已存在的键
av_dict_set(&dict, "key", "value1", 0);
av_dict_set(&dict, "key", "value2", 0); // 覆盖为 "value2"
// 2. 不覆盖已存在的键
av_dict_set(&dict, "key", "value1", 0);
av_dict_set(&dict, "key", "value2", AV_DICT_DONT_OVERWRITE); // 保持 "value1"
// 3. 追加到现有值
av_dict_set(&dict, "key", "value1", 0);
av_dict_set(&dict, "key", "value2", AV_DICT_APPEND);
// 结果: "value1,value2"
5. 实际应用场景
5.1 配置编码器参数
AVCodecContext *enc_ctx = avcodec_alloc_context3(codec);
AVDictionary *opts = NULL;
// 设置编码参数
av_dict_set(&opts, "preset", "medium", 0);
av_dict_set(&opts, "tune", "film", 0);
av_dict_set(&opts, "crf", "23", 0);
av_dict_set_int(&opts, "threads", 4, 0);
// 打开编码器
if (avcodec_open2(enc_ctx, codec, &opts) < 0) {
fprintf(stderr, "无法打开编码器\n");
}
// 注意:opts 会被 avcodec_open2 修改,未使用的选项会被移除
if (av_dict_count(opts) > 0) {
AVDictionaryEntry *e = NULL;
while ((e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
fprintf(stderr, "未知选项: %s\n", e->key);
}
}
av_dict_free(&opts);
5.2 配置解码器参数
AVCodec *decoder = avcodec_find_decoder(AV_CODEC_ID_H264);
AVCodecContext *dec_ctx = avcodec_alloc_context3(decoder);
AVDictionary *codec_opts = NULL;
// 设置解码参数
av_dict_set(&codec_opts, "flags2", "+fast", 0);
av_dict_set(&codec_opts, "flags", "+low_delay", 0);
av_dict_set(&codec_opts, "refcounted_frames", "1", 0);
avcodec_open2(dec_ctx, decoder, &codec_opts);
av_dict_free(&codec_opts);
5.3 配置输入输出格式
// 1. 输入格式选项
AVFormatContext *fmt_ctx = NULL;
AVDictionary *format_opts = NULL;
// RTSP 流选项
av_dict_set(&format_opts, "rtsp_transport", "tcp", 0);
av_dict_set(&format_opts, "stimeout", "5000000", 0); // 5秒超时
av_dict_set(&format_opts, "buffer_size", "1024000", 0);
avformat_open_input(&fmt_ctx, "rtsp://example.com/stream", NULL, &format_opts);
// 2. 输出格式选项
AVFormatContext *out_fmt_ctx = NULL;
AVDictionary *muxer_opts = NULL;
// 设置 MP4 复用器选项
av_dict_set(&muxer_opts, "movflags", "faststart+frag_keyframe+empty_moov", 0);
av_dict_set(&muxer_opts, "frag_duration", "1000000", 0); // 1秒分段
avformat_alloc_output_context2(&out_fmt_ctx, NULL, NULL, "output.mp4");
6. 特殊用法
6.1 批量设置选项
void set_encoder_options(AVDictionary **opts, const char *preset,
const char *tune, int crf, int bitrate) {
if (preset) av_dict_set(opts, "preset", preset, 0);
if (tune) av_dict_set(opts, "tune", tune, 0);
if (crf > 0) {
char crf_str[16];
snprintf(crf_str, sizeof(crf_str), "%d", crf);
av_dict_set(opts, "crf", crf_str, 0);
}
if (bitrate > 0) {
char br_str[16];
snprintf(br_str, sizeof(br_str), "%d", bitrate);
av_dict_set(opts, "b", br_str, 0);
}
}
6.2 条件设置
AVDictionary *create_stream_options(int video_width, int video_height,
int fps, int bitrate) {
AVDictionary *opts = NULL;
// 根据分辨率设置预设
if (video_width <= 640 && video_height <= 480) {
av_dict_set(&opts, "preset", "fast", 0);
} else if (video_width <= 1280 && video_height <= 720) {
av_dict_set(&opts, "preset", "medium", 0);
} else {
av_dict_set(&opts, "preset", "slow", 0);
}
// 设置其他参数
if (fps > 30) {
av_dict_set(&opts, "tune", "film", 0);
} else {
av_dict_set(&opts, "tune", "animation", 0);
}
return opts;
}
7. 错误处理
7.1 检查返回值
int set_option_safely(AVDictionary **dict, const char *key,
const char *value, int flags) {
int ret = av_dict_set(dict, key, value, flags);
if (ret < 0) {
char error_buf[AV_ERROR_MAX_STRING_SIZE];
av_strerror(ret, error_buf, sizeof(error_buf));
fprintf(stderr, "设置选项 '%s' 失败: %s\n", key, error_buf);
return ret;
}
return 0;
}
// 使用示例
AVDictionary *opts = NULL;
if (set_option_safely(&opts, "invalid_key", "value", 0) < 0) {
// 错误处理
}
7.2 内存安全设置
int set_option_with_allocated_strings(AVDictionary **dict,
char *key, char *value) {
// 注意:这里传递的是动态分配的字符串
int ret = av_dict_set(dict, key, value,
AV_DICT_DONT_STRDUP_KEY |
AV_DICT_DONT_STRDUP_VAL);
if (ret < 0) {
// 失败时需要手动释放内存
free(key);
free(value);
}
return ret;
}
8. 注意事项
-
字典生命周期:字典必须在不再使用时通过
av_dict_free()释放 -
字符串内存:默认情况下,
av_dict_set会复制字符串,调用者可以立即释放自己的字符串 -
指针有效性:使用
AV_DICT_DONT_STRDUP标志时,确保字符串在整个字典生命周期内有效 -
线程安全:
av_dict_set不是线程安全的 -
错误处理:总是检查返回值,特别是在处理动态分配的字符串时
-
选项验证:某些函数(如
avcodec_open2)会修改传入的字典,移除不支持的选项
av_dict_set是 FFmpeg 中最常用的配置函数之一,合理使用可以方便地传递各种参数和选项。理解其内存管理行为和标志位含义对于编写正确的 FFmpeg 程序至关重要。
2万+

被折叠的 条评论
为什么被折叠?



