[ffmpeg] av_opt_set 解析

背景

ffmpeg 创建编码器的时候,可以设置一些额外参数。可以通过两种方式,一是 av_opt_set,另一种是 avcodec_open2 最后一个参数传入。今天先分析一下第一种是什么设置进去的。

具体代码分析

av_opt_set 主要分成两部分,一个是在 obj 结构体中,找到 name 的地址。第二个是根据找到地址的类型, 解析 val,并将 val 赋值到该地址。

int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{int ret = 0;void *dst, *target_obj;const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);if (!o || !target_obj)return AVERROR_OPTION_NOT_FOUND;
FF_DISABLE_DEPRECATION_WARNINGSif (!val && (o->type != AV_OPT_TYPE_STRING &&o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT &&o->type != AV_OPT_TYPE_IMAGE_SIZE &&o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR &&
#if FF_API_OLD_CHANNEL_LAYOUTo->type != AV_OPT_TYPE_CHANNEL_LAYOUT &&
#endifo->type != AV_OPT_TYPE_BOOL))return AVERROR(EINVAL);
FF_ENABLE_DEPRECATION_WARNINGSif (o->flags & AV_OPT_FLAG_READONLY)return AVERROR(EINVAL);if (o->flags & AV_OPT_FLAG_DEPRECATED)av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help);dst = ((uint8_t *)target_obj) + o->offset;switch (o->type) {case AV_OPT_TYPE_BOOL:return set_string_bool(obj, o, val, dst);case AV_OPT_TYPE_STRING:return set_string(obj, o, val, dst);case AV_OPT_TYPE_BINARY:return set_string_binary(obj, o, val, dst);case AV_OPT_TYPE_FLAGS:case AV_OPT_TYPE_INT:case AV_OPT_TYPE_INT64:case AV_OPT_TYPE_UINT64:case AV_OPT_TYPE_FLOAT:case AV_OPT_TYPE_DOUBLE:case AV_OPT_TYPE_RATIONAL:return set_string_number(obj, target_obj, o, val, dst);case AV_OPT_TYPE_IMAGE_SIZE:return set_string_image_size(obj, o, val, dst);case AV_OPT_TYPE_VIDEO_RATE: {AVRational tmp;ret = set_string_video_rate(obj, o, val, &tmp);if (ret < 0)return ret;return write_number(obj, o, dst, 1, tmp.den, tmp.num);}case AV_OPT_TYPE_PIXEL_FMT:return set_string_pixel_fmt(obj, o, val, dst);case AV_OPT_TYPE_SAMPLE_FMT:return set_string_sample_fmt(obj, o, val, dst);case AV_OPT_TYPE_DURATION:{int64_t usecs = 0;if (val) {if ((ret = av_parse_time(&usecs, val, 1)) < 0) {av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val);return ret;}}if (usecs < o->min || usecs > o->max) {av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0);return AVERROR(ERANGE);}*(int64_t *)dst = usecs;return 0;}case AV_OPT_TYPE_COLOR:return set_string_color(obj, o, val, dst);
#if FF_API_OLD_CHANNEL_LAYOUT
FF_DISABLE_DEPRECATION_WARNINGScase AV_OPT_TYPE_CHANNEL_LAYOUT:if (!val || !strcmp(val, "none")) {*(int64_t *)dst = 0;} else {int64_t cl = av_get_channel_layout(val);if (!cl) {av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val);ret = AVERROR(EINVAL);}*(int64_t *)dst = cl;return ret;}break;
FF_ENABLE_DEPRECATION_WARNINGS
#endifcase AV_OPT_TYPE_CHLAYOUT:ret = set_string_channel_layout(obj, o, val, dst);if (ret < 0) {av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val);ret = AVERROR(EINVAL);}return ret;case AV_OPT_TYPE_DICT:return set_string_dict(obj, o, val, dst);}av_log(obj, AV_LOG_ERROR, "Invalid option type.\n");return AVERROR(EINVAL);
}

找到 name 的地址

主要关注 av_opt_next 函数,第一次进去返回 option 地址,之后进去每次往后移动一个 option。并将获得的 option name 与传入的 name 进行比较。

const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,int opt_flags, int search_flags, void **target_obj)
{const AVClass  *c;const AVOption *o = NULL;if(!obj)return NULL;c= *(AVClass**)obj;if (!c)return NULL;// 非必要,先不看if (search_flags & AV_OPT_SEARCH_CHILDREN) {if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) {void *iter = NULL;const AVClass *child;while (child = av_opt_child_class_iterate(c, &iter))if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL))return o;} else {void *child = NULL;while (child = av_opt_child_next(obj, child))if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj))return o;}}while (o = av_opt_next(obj, o)) {if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&((!unit && o->type != AV_OPT_TYPE_CONST) ||(unit  && o->type == AV_OPT_TYPE_CONST && o->unit && !strcmp(o->unit, unit)))) {if (target_obj) {if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ))*target_obj = obj;else*target_obj = NULL;}return o;}}return NULL;
}const AVOption *av_opt_next(const void *obj, const AVOption *last)
{const AVClass *class;if (!obj)return NULL;class = *(const AVClass**)obj;if (!last && class && class->option && class->option[0].name)return class->option;if (last && last[1].name)return ++last;return NULL;
}

以 aacenc.c 中的 aacenc_options 进行分析,可以注意到最后一个 option 是 NULL,和codec_list 一样的手法。

static const AVOption aacenc_options[] = {{"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "coder"},{"anmr",     "ANMR method",               0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR},    INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},{"twoloop",  "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},{"fast",     "Default fast search",       0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST},    INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},{"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS},{"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},{"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},{"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},{"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},{"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},{"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},FF_AAC_PROFILE_OPTS{NULL}
};typedef struct AVOption {const char *name;/*** short English help text* @todo What about other languages?*/const char *help;/*** The offset relative to the context structure where the option* value is stored. It should be 0 for named constants.*/int offset;enum AVOptionType type;/*** the default value for scalar options*/union {int64_t i64;double dbl;const char *str;/* TODO those are unused now */AVRational q;} default_val;double min;                 ///< minimum valid value for the optiondouble max;                 ///< maximum valid value for the optionint flags;
#define AV_OPT_FLAG_ENCODING_PARAM  1   ///< a generic parameter which can be set by the user for muxing or encoding
#define AV_OPT_FLAG_DECODING_PARAM  2   ///< a generic parameter which can be set by the user for demuxing or decoding
#define AV_OPT_FLAG_AUDIO_PARAM     8
#define AV_OPT_FLAG_VIDEO_PARAM     16
#define AV_OPT_FLAG_SUBTITLE_PARAM  32
/*** The option is intended for exporting values to the caller.*/
#define AV_OPT_FLAG_EXPORT          64
/*** The option may not be set through the AVOptions API, only read.* This flag only makes sense when AV_OPT_FLAG_EXPORT is also set.*/
#define AV_OPT_FLAG_READONLY        128
#define AV_OPT_FLAG_BSF_PARAM       (1<<8) ///< a generic parameter which can be set by the user for bit stream filtering
#define AV_OPT_FLAG_RUNTIME_PARAM   (1<<15) ///< a generic parameter which can be set by the user at runtime
#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering
#define AV_OPT_FLAG_DEPRECATED      (1<<17) ///< set if option is deprecated, users should refer to AVOption.help text for more information
#define AV_OPT_FLAG_CHILD_CONSTS    (1<<18) ///< set if option constants can also reside in child objects
//FIXME think about enc-audio, ... style flags/*** The logical unit to which the option belongs. Non-constant* options and corresponding named constants share the same* unit. May be NULL.*/const char *unit;
} AVOption;

根据找到地址的类型, 解析 val,并将 val 赋值到该地址

以 set_string_bool 举例。可以看见如果传入 auto,则会赋值 -1;true,y,yes,enable,enabled,on 赋值 1,false,n,no,disable,disabled,off 为0。
其他类型的赋值,大家可以去看具体的函数。

static int set_string_bool(void *obj, const AVOption *o, const char *val, int *dst)
{int n;if (!val)return 0;if (!strcmp(val, "auto")) {n = -1;} else if (av_match_name(val, "true,y,yes,enable,enabled,on")) {n = 1;} else if (av_match_name(val, "false,n,no,disable,disabled,off")) {n = 0;} else {char *end = NULL;n = strtol(val, &end, 10);if (val + strlen(val) != end)goto fail;}if (n < o->min || n > o->max)goto fail;*dst = n;return 0;fail:av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as boolean\n", val);return AVERROR(EINVAL);
}

寻找地址

target_obj 就是 av_opt_set 传入的地址, offset 是每个 option,在编码器结构体中的偏移量。 offsetof(AACEncContext, options.coder)

dst = ((uint8_t *)target_obj) + o->offset;
#define offsetof(s,m) ((size_t)&(((s*)0)->m))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/203561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打工人副业变现秘籍,某多/某手变现底层引擎-Stable Diffusion图生图

我们都知道,模型在运算时是根据我们提供的提示内容来确定绘图方向,如果没有提示信息,模型只能根据此前的学习经验来自行发挥。在之前的文生图篇,我们介绍了如何通过提示词来控制图像内容,但想要实现准确的出图效果,只靠简短的提示词是很难满足实际需求的。 AI 绘画的随机…

SpringBoot+SSM项目实战 苍穹外卖(4) day4作业

继续上一节的内容&#xff0c;本节是作业课程&#xff0c;要求独立完成套餐管理模块所有业务功能&#xff0c;包括&#xff1a;新增套餐、套餐分页查询、删除套餐、修改套餐、起售停售套餐。 目录 新增套餐根据分类id查询菜品功能新增套餐功能 套餐分页查询删除套餐根据id查询套…

如何设置不同的网页标题(react)

通常&#xff0c;当我们写一个h5或者网站时&#xff0c;需要根据页面的业务来自定义网页标题。 这个本来是在入口html文件中设置的&#xff0c;但唯一。 <head><meta charset"UTF-8" /><!-- <link rel"icon" type"image/svgxml&qu…

【Flink on k8s】- 4 - 在 Kubernetes 上运行容器

目录 1、准备 k8s 集群环境、Docker 环境 2、启用 kubernetes 2.1 查询 k8s 集群基本状态

Java二阶知识点总结(一)Maven

一、Maven概念 Maven是一个项目管理工具&#xff0c;其主要作用有2点 依赖管理&#xff1a;管理项目依赖的各种jar包自动构建&#xff1a;项目构建的过程&#xff0c;从编译、测试、运行、打包到安装的过程可以一键执行 二、Maven工程的目录结构 src/main/java&#xff1a;…

要求CHATGPT高质量回答的艺术:提示工程技术的完整指南—第 14 章:受控生成提示

要求CHATGPT高质量回答的艺术&#xff1a;提示工程技术的完整指南—第 14 章&#xff1a;受控生成提示 受控生成提示是一种可以高度控制输出结果的文本生成技术。 具体做法是为模型提供一组特定的输入&#xff0c;如模板、特定词汇或一组约束&#xff0c;用于指导生成过程。 …

C++代码自动化

摘要 在程序员的日常工作中&#xff0c;写代码并不是一件很枯燥乏味的事&#xff0c;因为本身通过代码已经实现了很多单靠人无法完成的工作。但随着代码工程量的加剧&#xff0c;代码逐渐的冗长而复杂&#xff0c;功能的调理型也逐渐的不清晰&#xff0c;这种现象一方面使得代…

Linux join命令教程:如何合并两个文件的行(附实例详解和注意事项)

Linux join命令介绍 Linux的join命令是一个非常有用的工具&#xff0c;它可以合并两个文件的行&#xff0c;这两个文件的行是通过一个公共字段来匹配的。这个命令可以为你的静态数据文件添加一些动态性。如果你想从两个文本文件中通过匹配一个公共字段来合并数据&#xff0c;你…

前端面试JS—数组的常用方法

目录 一、操作&#xff08;增/删/改/查&#xff09; 增 删 改 查 二、排序 三、转换 四、迭代 一、操作&#xff08;增/删/改/查&#xff09; 数组基本操作有 增、删、改、查&#xff0c;需要注意哪些方法会对原数组产生影响&#xff0c;哪些方法不会 增 下面前三种是对…

【S32K144】MCAL基础工程搭建

目录 一、在S32DS创建Application Project 二、MCAL工程 三、基于MCAL的集成 以下示例基于S32K144EVB开发板进行。 一、在S32DS创建Application Project &#xff08;1&#xff09;新建工程Application Project &#xff08;2&#xff09;工程配置 &#xff08;3&#xff…

正则表达式(5):常用符号

正则表达式&#xff08;5&#xff09;&#xff1a;常用符号 小结 本博文转载自 在本博客中&#xff0c;”正则表达式”为一系列文章&#xff0c;如果你想要从头学习怎样在Linux中使用正则&#xff0c;可以参考此系列文章&#xff0c;直达链接如下&#xff1a; 在Linux中使用正…

PHP处理字符串

一&#xff1a;字符串分割成数组 日常工作中&#xff0c;如果需要把一个字符串分割成数组&#xff0c;我们一般使用 explode() 函数对字符串进行分割&#xff0c;具体代码如下所示&#xff1a; <?php$str PHP|python|java|js|css|html; $arr explode(|,$str); print_r(…

linux的磁盘管理

Linux 提供了多种工具和技术来进行磁盘管理。下面是对 Linux 磁盘管理的详细解释&#xff1a; 磁盘和分区&#xff1a; 磁盘&#xff08;硬盘&#xff09;&#xff1a;Linux 系统中的磁盘通常是通过 SATA、SCSI、NVMe 等接口连接的物理硬盘。可以使用工具如 lsblk、fdisk、pa…

二叉平衡树

一直想深入的研究一下&#xff0c;并手写平衡二叉树的插入、删除代码。 二叉树是动态查找的典范&#xff0c;但在极限情况下&#xff0c;二叉树的查找效果等同于链表&#xff0c;而平衡二叉树可以完美的达到 log ⁡ 2 n \log_2 n log2​n。 AVL简称平衡二叉树&#xff0c;缩写…

DAPP开发【11】IPFS星际文件管理系统

IPFS&#xff08;InterPlanetary File System&#xff09;是一个点对点的分布式文件系统&#xff0c;旨在创建一个更快速、更安全和更开放的 Web。它不同于传统的 HTTP 协议&#xff0c;因为它不需要使用一个固定的地址来访问文件&#xff0c;而是通过一个基于内容寻址的系统&a…

HNU程序设计 类和对象练习(小班)

学生类Student类的设计与实现 要求: 创建一个 Student 类&#xff0c;包含公有数据成员&#xff1a;姓名&#xff08;字符串&#xff09;、学号、性别、 3 门课程成绩 ( 结构 体形式&#xff0c;属性包含课程名和分数 ) &#xff0c;以及私有属性身份证信息。 &#xff08;…

python 实现 excle读取时间序列数据并画图显示

示例&#xff1a;Excle第一列为时间&#xff0c;第二列Num为秒为单位的时间&#xff0c;第三列到第九列为观测的温度数据。第一行为标签信息&#xff0c;第二行开始是数据。 实现功能&#xff1a;以第二列秒为单位的数据为横坐标&#xff0c;纵坐标为温度&#xff0c;将第三列到…

Linux系统调试课:I2C tools调试工具

文章目录 一、如何使用I2C tools测试I2C外设1、I2C tools概述: 2、下载I2C tools源码:3、编译I2C tools源码: 4、i2cdetect 5、i2cget 6、i2cdump

Vue+ElementUI技巧分享:结合Sortablejs实现表格行拖拽

文章目录 前言准备工作示例代码代码说明1. 引入依赖和组件结构2. 组件数据和生命周期3. 实现拖拽功能4. 更新数据和服务器同步 运行效果总结 前言 在很多动态网页应用中&#xff0c;用户界面的交互性是提高用户体验的关键。在 Vue.js 中&#xff0c;结合 Element UI 和 sortab…

rust从0开始写项目-06-如何接受命令行参数clap-01

写web项目或者app等&#xff0c;必不可少的要接受参数和校验参数的准确性&#xff0c;基本也是项目开始的第一步&#xff0c;那么我们今天来看下rust提供了哪些优秀的crates 关注 vx golang技术实验室&#xff0c;获取更多golang、rust好文 Part1一、clap_v3 本来是想用structO…