当前位置: 首页 > news >正文

FFmpeg有理数相关的源码:AVRational结构体和其相关的函数分析

  =================================================================

AVRational结构体和其相关的函数分析:

FFmpeg有理数相关的源码:AVRational结构体和其相关的函数分析

FFmpeg源码:av_reduce函数分析

 =================================================================

一、引言

有理数是整数(正整数、0、负整数)和分数的统称,是整数和分数的集合。整数也可看作是分母是1的分数。不是有理数的实数称为无理数,即无理数的小数部分是无限不循环的数。

AVRational是FFmpeg源码中的一个结构体,用来抽象有理数。为什么不使用double类型(浮点数)呢?虽然有理数可以表示为浮点数,但浮点操作的转换过程是一个有损过程,使用浮点数计算可能会导致有理数出现精度误差;另一方面,FFmpeg的特性要求高精度的时间戳计算。AVRational结构体和其相关函数可以作为一个通用接口,用于操作作为分子和分母对的有理数。
AVRational相关的函数都带有`_q`后缀,表示数学符号“ℚ”(Q),表示所有有理数的集合。

二、AVRational结构体的声明

AVRational结构体定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavutil/rational.h中:

/*** Rational number (pair of numerator and denominator).*/
typedef struct AVRational{int num; ///< Numeratorint den; ///< Denominator
} AVRational;

FFmpeg源码中使用AVRational结构体来表示有理数。注意:执行AVRational结构体相关的函数时最好都要在函数外部判断其分母是否为0。有理数的分母是不能等于0的,分母等于0是没有意义的。分母为0可能会导致除数为0,从而导致程序崩溃。这些函数内部都不会对分母为0的情况进行处理。

成员变量num:有理数的分子

成员变量den:有理数的分母

三、av_make_q函数的定义

av_make_q函数定义在libavutil/rational.h中:

/*** Create an AVRational.** Useful for compilers that do not support compound literals.** @note The return value is not reduced.* @see av_reduce()*/
static inline AVRational av_make_q(int num, int den)
{AVRational r = { num, den };return r;
}

其作用是:给有理数的分子和分母赋值并返回。

形参num:输入型参数。传递给有理数分子的值。执行av_make_q函数后,有理数分子的值为num。

形参den:输入型参数。传递给有理数分母的值。执行av_make_q函数后,有理数分母的值为den。

返回值:返回被赋值的AVRational类型的有理数。

四、av_cmp_q函数的定义

(一)av_cmp_q函数的定义

av_cmp_q函数定义在libavutil/rational.h中:

/*** Compare two rationals.** @param a First rational* @param b Second rational** @return One of the following values:*         - 0 if `a == b`*         - 1 if `a > b`*         - -1 if `a < b`*         - `INT_MIN` if one of the values is of the form `0 / 0`*/
static inline int av_cmp_q(AVRational a, AVRational b){const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1;else if(b.den && a.den) return 0;else if(a.num && b.num) return (a.num>>31) - (b.num>>31);else                    return INT_MIN;
}

其作用是:比较两个有理数的大小。

形参a:输入型参数。被比较的第一个有理数。

形参b:输入型参数。被比较的第二个有理数。

返回值:如果a的值等于b,返回0;如果a>b,返回1;如果a<b,返回-1;如果a或b中有一个有理数的分子和分母同时为0,返回`INT_MIN`(-2147483648)。注意:这函数非常奇怪,如果a或b中有一个有理数的分子不为0但分母为0,这函数不会返回`INT_MIN`;只有当a或b中有一个有理数的分子和分母同时为0,才会返回`INT_MIN`。av_cmp_q函数内部没有对a和b中分子不为0但分母为0的情况进行处理。所以在使用该函数之前最好要先在其外部判断a和b分母是否为0,避免被比较的有理数分母出现0的情况。

(二)av_cmp_q函数的使用例子

编写测试例子main.c,在Ubuntu中使用9.4.0版本的gcc编译通过:

#include <stdio.h>
#include <stdint.h>
#include <limits.h>typedef struct AVRational{int num; ///< Numeratorint den; ///< Denominator
} AVRational;static inline AVRational av_make_q(int num, int den)
{AVRational r = { num, den };return r;
}static inline int av_cmp_q(AVRational a, AVRational b){const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1;else if(b.den && a.den) return 0;else if(a.num && b.num) return (a.num>>31) - (b.num>>31);else                    return INT_MIN;
}int main()
{AVRational a = av_make_q(1, 2);AVRational b = av_make_q(1, 3);printf("av_cmp_q(a, b): %d\n", av_cmp_q(a, b));AVRational c = av_make_q(65536, 1);AVRational d = av_make_q(2, 0);printf("av_cmp_q(c, d): %d\n", av_cmp_q(c, d));AVRational e = av_make_q(0, 0);AVRational f = av_make_q(1, 3);printf("av_cmp_q(e, f): %d\n", av_cmp_q(e, f));return 0;
}

输出如下:

五、av_q2d函数的定义

av_q2d函数定义在libavutil/rational.h中:

/*** Convert an AVRational to a `double`.* @param a AVRational to convert* @return `a` in floating-point form* @see av_d2q()*/
static inline double av_q2d(AVRational a){return a.num / (double) a.den;
}

该函数作用是:将有理数从AVRational类型转换为double类型(双精度浮点数)。该操作可能会造成精度丢失。

形参a:输入型参数。被转换的有理数。

返回值:由形参a转换出来的double类型数值。

六、av_reduce函数的定义

详情请看《FFmpeg源码:av_reduce函数分析》

七、av_mul_q函数的定义

av_mul_q函数定义在libavutil/rational.c中:

/*** Multiply two rationals.* @param b First rational* @param c Second rational* @return b*c*/
AVRational av_mul_q(AVRational b, AVRational c)
{av_reduce(&b.num, &b.den,b.num * (int64_t) c.num,b.den * (int64_t) c.den, INT_MAX);return b;
}

该函数作用是:将有理数b * c的结果作为返回值返回。可以看到它内部调用了av_reduce函数。

八、av_div_q函数的定义

av_div_q函数定义在libavutil/rational.c中:

/*** Divide one rational by another.* @param b First rational* @param c Second rational* @return b/c*/
AVRational av_div_q(AVRational b, AVRational c)
{return av_mul_q(b, (AVRational) { c.den, c.num });
}

该函数作用是:将有理数b ÷ c的结果作为返回值返回。

九、av_add_q函数的定义

av_add_q函数定义在libavutil/rational.c中:

/*** Add two rationals.* @param b First rational* @param c Second rational* @return b+c*/
AVRational av_add_q(AVRational b, AVRational c) {av_reduce(&b.num, &b.den,b.num * (int64_t) c.den +c.num * (int64_t) b.den,b.den * (int64_t) c.den, INT_MAX);return b;
}

该函数作用是:将有理数b + c的结果作为返回值返回。

十、av_sub_q函数的定义

av_sub_q函数定义在libavutil/rational.c中:

/*** Subtract one rational from another.* @param b First rational* @param c Second rational* @return b-c*/
AVRational av_sub_q(AVRational b, AVRational c)
{return av_add_q(b, (AVRational) { -c.num, c.den });
}

该函数作用是:将有理数b - c的结果作为返回值返回。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 英伟达显卡查看占用情况
  • 设计模式实战:报表生成系统的设计与实现
  • Chapter 22 数据可视化——折线图
  • Chapter 26 Python魔术方法
  • 用phpstudy搭建MySQL数据库
  • WebKit 的简介及工作流程
  • 科普文:JUC系列之多线程门闩同步器CountDownLatch的使用和源码
  • C++STL专题-string类
  • 低代码: 技术实现概述
  • 部署k8s+conatinerd环境
  • 【学习笔记】后缀自动机(SAM)
  • 【MySQL】索引——索引的引入、认识磁盘、磁盘的组成、扇区、磁盘访问、磁盘和MySQL交互、索引的概念
  • 微信小程序 - 自定义计数器 - 优化(键盘输入校验)
  • 在VScode中导入conda环境的记录【原创】
  • 数据保险箱:SQL Server数据库备份加密的高级策略
  • __proto__ 和 prototype的关系
  • CentOS从零开始部署Nodejs项目
  • Java,console输出实时的转向GUI textbox
  • Kibana配置logstash,报表一体化
  • NSTimer学习笔记
  • Python利用正则抓取网页内容保存到本地
  • Service Worker
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 仿天猫超市收藏抛物线动画工具库
  • 工程优化暨babel升级小记
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 事件委托的小应用
  • 通信类
  • 消息队列系列二(IOT中消息队列的应用)
  • 在Mac OS X上安装 Ruby运行环境
  • 正则表达式
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • "无招胜有招"nbsp;史上最全的互…
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (2)STM32单片机上位机
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (ibm)Java 语言的 XPath API
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (js)循环条件满足时终止循环
  • (MATLAB)第五章-矩阵运算
  • (vue)el-tabs选中最后一项后更新数据后无法展开
  • (笔试题)分解质因式
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (论文阅读11/100)Fast R-CNN
  • (三)SvelteKit教程:layout 文件
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)mysql使用Navicat 导出和导入数据库
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .L0CK3D来袭:如何保护您的数据免受致命攻击