FFmpeg源码:av_reduce函数分析

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

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

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

FFmpeg源码:av_reduce函数分析

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

一、av_reduce函数的声明

av_reduce函数声明在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavutil/rational.h中:

/*** Reduce a fraction.** This is useful for framerate calculations.** @param[out] dst_num Destination numerator* @param[out] dst_den Destination denominator* @param[in]      num Source numerator* @param[in]      den Source denominator* @param[in]      max Maximum allowed values for `dst_num` & `dst_den`* @return 1 if the operation is exact, 0 otherwise*/
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max);

该函数作用是:化简有理数(一般用来化简分数)。比如分数4/6(六分之四),化简后为2/3(三分之二)。需要对AVRational结构体进行加减乘除(四则运算)时会调用该函数;av_reduce函数也可以用来计算视频帧率。具体可以参考:《音视频入门基础:H.264专题(15)——FFmpeg源码中通过SPS属性获取视频帧率的实现》。

形参dst_num:输出型参数。执行av_reduce函数后,dst_num指向的整形变量值会变为“被化简后的有理数中的分子”。

形参dst_den:输出型参数。执行av_reduce函数后,dst_den指向的整形变量值会变为“被化简后的有理数中的分母”。

形参num:输入型参数。需要被化简的有理数中的分子。

形参den:输入型参数。需要被化简的有理数中的分母。

形参max:输入型参数,用于进行限制。被化简后的有理数中的分子和分母的绝对值都不能超过该值。

返回值:1:化简结果是准确的;0:化简结果不准确。

二、av_reduce函数的定义

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

int av_reduce(int *dst_num, int *dst_den,int64_t num, int64_t den, int64_t max)
{AVRational a0 = { 0, 1 }, a1 = { 1, 0 };int sign = (num < 0) ^ (den < 0);int64_t gcd = av_gcd(FFABS(num), FFABS(den));if (gcd) {num = FFABS(num) / gcd;den = FFABS(den) / gcd;}if (num <= max && den <= max) {a1 = (AVRational) { num, den };den = 0;}while (den) {uint64_t x        = num / den;int64_t next_den  = num - den * x;int64_t a2n       = x * a1.num + a0.num;int64_t a2d       = x * a1.den + a0.den;if (a2n > max || a2d > max) {if (a1.num) x =          (max - a0.num) / a1.num;if (a1.den) x = FFMIN(x, (max - a0.den) / a1.den);if (den * (2 * x * a1.den + a0.den) > num * a1.den)a1 = (AVRational) { x * a1.num + a0.num, x * a1.den + a0.den };break;}a0  = a1;a1  = (AVRational) { a2n, a2d };num = den;den = next_den;}av_assert2(av_gcd(a1.num, a1.den) <= 1U);av_assert2(a1.num <= max && a1.den <= max);*dst_num = sign ? -a1.num : a1.num;*dst_den = a1.den;return den == 0;
}

三、av_reduce函数的内部实现分析

av_reduce函数中,首先通过异或(^)运算符判断输入的有理数的正负。变量sign的值为0:输入的有理数为正数;sign值为1:输入的有理数为负数或0;

int sign = (num < 0) ^ (den < 0);

然后通过av_gcd函数得到输入的有理数的分子和分母的最大公约数(关于av_gcd函数的用法可以参考:《FFmpeg源码:av_gcd函数分析》):

int64_t gcd = av_gcd(FFABS(num), FFABS(den));

FFABS是宏,定义在libavutil/common.h中,作用是得到绝对值:

/*** Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they* are not representable as absolute values of their type. This is the same* as with *abs()* @see FFNABS()*/
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))

如果最大公约数大于0,让输出的有理数中的分子和分母都除以最大公约数(约分),从而让分数化简。分数的化简的其中一种方法是:化成分数乘法,求出比值,再把比值写成比号链接的形式。即可把一个分数化成和它相等,但分子和分母都比较小的分数,叫做约分,约分时根据分数的基本性质一次性约分(用最大公因数分别去除分子、分母):

if (gcd) {num = FFABS(num) / gcd;den = FFABS(den) / gcd;}

限制化简后的有理数中的分子和分母的绝对值都不能超过形参max的值:

    if (num <= max && den <= max) {a1 = (AVRational) { num, den };den = 0;}

让输出型参数dst_num和dst_den分别得到化简后的有理数的分子和分母:

*dst_num = sign ? -a1.num : a1.num;*dst_den = a1.den;return den == 0;

四、av_reduce函数的使用例子

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

#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include <features.h>#ifdef __GNUC__
#    define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#    define AV_GCC_VERSION_AT_MOST(x,y)  (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y))
#else
#    define AV_GCC_VERSION_AT_LEAST(x,y) 0
#    define AV_GCC_VERSION_AT_MOST(x,y)  0
#endif#ifndef av_always_inline
#if AV_GCC_VERSION_AT_LEAST(3,1)
#    define av_always_inline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#    define av_always_inline __forceinline
#else
#    define av_always_inline inline
#endif
#endif#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
#    define av_const __attribute__((const))
#else
#    define av_const
#endif#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define av_assert2(cond) ((void)0)#ifdef __USE_ISOC99
__extension__ extern long long int llabs (long long int __x)__THROW __attribute__ ((__const__)) __wur;
#endif#ifndef ff_ctzll
#define ff_ctzll ff_ctzll_ctypedef struct AVRational{int num; ///< Numeratorint den; ///< Denominator
} AVRational;/* We use the De-Bruijn method outlined in:* http://supertech.csail.mit.edu/papers/debruijn.pdf. */
static av_always_inline av_const int ff_ctzll_c(long long v)
{static const uint8_t debruijn_ctz64[64] = {0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12};return debruijn_ctz64[(uint64_t)((v & -v) * 0x022FDD63CC95386DU) >> 58];
}
#endifint64_t av_gcd(int64_t a, int64_t b) {int za, zb, k;int64_t u, v;if (a == 0)return b;if (b == 0)return a;za = ff_ctzll(a);zb = ff_ctzll(b);k  = FFMIN(za, zb);u = llabs(a >> za);v = llabs(b >> zb);while (u != v) {if (u > v)FFSWAP(int64_t, v, u);v -= u;v >>= ff_ctzll(v);}return (uint64_t)u << k;
}/*** Reduce a fraction.** This is useful for framerate calculations.** @param[out] dst_num Destination numerator* @param[out] dst_den Destination denominator* @param[in]      num Source numerator* @param[in]      den Source denominator* @param[in]      max Maximum allowed values for `dst_num` & `dst_den`* @return 1 if the operation is exact, 0 otherwise*/
int av_reduce(int *dst_num, int *dst_den,int64_t num, int64_t den, int64_t max)
{AVRational a0 = { 0, 1 }, a1 = { 1, 0 };int sign = (num < 0) ^ (den < 0);int64_t gcd = av_gcd(FFABS(num), FFABS(den));if (gcd) {num = FFABS(num) / gcd;den = FFABS(den) / gcd;}if (num <= max && den <= max) {a1 = (AVRational) { num, den };den = 0;}while (den) {uint64_t x        = num / den;int64_t next_den  = num - den * x;int64_t a2n       = x * a1.num + a0.num;int64_t a2d       = x * a1.den + a0.den;if (a2n > max || a2d > max) {if (a1.num) x =          (max - a0.num) / a1.num;if (a1.den) x = FFMIN(x, (max - a0.den) / a1.den);if (den * (2 * x * a1.den + a0.den) > num * a1.den)a1 = (AVRational) { x * a1.num + a0.num, x * a1.den + a0.den };break;}a0  = a1;a1  = (AVRational) { a2n, a2d };num = den;den = next_den;}av_assert2(av_gcd(a1.num, a1.den) <= 1U);av_assert2(a1.num <= max && a1.den <= max);*dst_num = sign ? -a1.num : a1.num;*dst_den = a1.den;return den == 0;
}int main()
{int dst_num1 = 0;int dst_den1 = 0;int ret = av_reduce(&dst_num1, &dst_den1, 4, 6, 5);printf("ret:%d, dst_num1:%d, dst_den1:%d\n", ret, dst_num1, dst_den1);int dst_num2 = 0;int dst_den2 = 0;ret = av_reduce(&dst_num2, &dst_den2, -4, 6, 5);printf("ret:%d, dst_num2:%d, dst_den2:%d\n", ret, dst_num2, dst_den2);int dst_num3 = 0;int dst_den3 = 0;ret = av_reduce(&dst_num3, &dst_den3, -4, 6, 1);printf("ret:%d, dst_num3:%d, dst_den3:%d\n", ret, dst_num3, dst_den3);return 0;
}

输出如下:

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

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

相关文章

【计算机操作系统】同步与互斥的基本概念

同步与互斥的基本概念 进程同步的概念 知识点回顾&#xff1a;进程具有异步性&#xff0c;异步性是指&#xff0c;各并发执行的进程以各自独立的、不可预知的速度向前推进 并发性带来了异步性&#xff0c;有时需要通过进程同步解决这种异步问题&#xff0c;有的进程之间需要…

JVM的面试考点

JVM内存划分 1.堆,整个内存区域中,内存最大的区域,放的都是new出来的对象,new类名这一部分存放在堆中, 而这个scanner是一个临时变量,这个scanner的地址存放在栈上,scanner里面存放的值是new类名这个对象的首地址 2.栈,分为JVM虚拟机栈(Java代码),和本地方法栈(C),这个栈包含了…

如何提前预防网络威胁

一、引言 随着信息技术的迅猛进步&#xff0c;网络安全议题愈发凸显&#xff0c;成为社会各界不可忽视的重大挑战。近年来&#xff0c;一系列网络安全事件的爆发&#xff0c;如同惊雷般震撼着个人、企业及国家的安全防线&#xff0c;揭示了信息安全保护的紧迫性与复杂性。每一…

2024年第五届“华数杯”全国大学生数学建模竞赛C题-老外游中国(代码+成品论文+讲解)

目录 &#x1f495;一、问题重述&#x1f495; &#x1f438;问题 1&#x1f438; &#x1f438;问题 2&#x1f438; &#x1f438;问题 3&#x1f438; &#x1f438;问题 4&#x1f438; &#x1f438;问题 5&#x1f438; &#x1f495;二、解题思路&#x1f495; …

图解RocketMQ之如何实现顺序消息

大家好&#xff0c;我是苍何。 顺序消息是业务中常用的功能之一&#xff0c;而 RocketMQ 默认发送的事普通无序的消息&#xff0c;那该如何发送顺序消息呢&#xff1f; 要保证消息的顺序&#xff0c;要从生产端到 broker 消息存储&#xff0c;再到消费消息都要保证链路的顺序…

【C++】二维数组 数组名

二维数组名用途 1、查看所占内存空间 2、查看二维数组首地址 针对第一种用途&#xff0c;还可以计算数组有多少行、多少列、多少元素 针对第二种用途&#xff0c;数组元素、行数、列数都是连续的&#xff0c;且相差地址是有规律的 下面是一个实例 #include<iostream&g…

Spring源码解析(29)之AOP动态代理对象创建过程分析

一、前言 在上一节中我们已经介绍了在createBean过程中去执行AspectJAutoProxyCreator的after方法&#xff0c;然后去获取当前bean适配的advisor&#xff0c;如果还不熟悉的可以去看下之前的博客&#xff0c;接下来我们分析Spring AOP是如何创建代理对象的&#xff0c;在此之前…

【目标检测类】YOLOv5网络模型结构基本原理讲解

1. 基本概念 YOLOv5模型结构主要包括以下组成部分&#xff1a;‌ 输入端&#xff1a;‌YOLOv5的输入端采用了多种技术来增强模型的性能&#xff0c;‌包括Mosaic数据增强、‌自适应锚框计算、‌以及自适应图片缩放。‌这些技术有助于提高模型的泛化能力和适应不同尺寸的输入图…

MySQL基础操作全攻略:增删改查实用指南(中)

本节目标&#xff1a; NOT NULL - 指示某列不能存储 NULL 值。 UNIQUE - 保证某列的每行必须有唯一的值。 DEFAULT - 规定没有给列赋值时的默认值。 PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列&#xff08;或两个列多个列的结合&#xff09;有唯一标 识&am…

【C++】模拟实现stack

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:实战项目集 ⚙️操作环境:Visual Studio 2022 ​ 目录 一.了解项目功能 &#x1f4cc;了解stack官方标准 &#x1f4cc;了解模拟实现stack 二.逐步实现项目功能模块及其逻辑详解 &#x1f4cc;实现stack成员变量 &…

【Linux】进程间通信(管道通信、共享内存通信)

一.什么是进程间通信 进程间通信这五个字很好理解&#xff0c;就是进程和进程之间通信。 那么为什么要有进程间通信呢&#xff1f; 1.数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 2.资源共享&#xff1a;多个进程之间共享同样的资源 3.通知事件&#xff1a;一…

遗传算法与深度学习实战——生命模拟与进化论

遗传算法与深度学习实战——生命模拟与进化论 0. 前言1. 模拟进化1.1 代码实现1.2 代码改进 2. 达尔文进化论3. 自然选择和适者生存3.1 适者生存3.2 进化计算中的生物学 小结系列链接 0. 前言 生命模拟通过计算机模拟生物体的基本特征、遗传机制、环境互动等&#xff0c;试图模…

WPF 依赖属性 IsHitTestVisible

IsHitlTestVisible 仅影响本身的元素&#xff08;含内部包含的子元素&#xff09;&#xff0c;不影响父元素效果&#xff0c;且事件会传递到父元素。 Eg&#xff1a; 如父元素有click事件&#xff0c; 子元素设置了IsHitTestVisiblefalse&#xff0c; 当鼠标单击这个子元素时&…

Android 埋点信息分析——内存篇

源码基于&#xff1a;Android U 0. 前言 在前一篇《Android statsd 埋点简析》一文中简单剖析了Android 埋点采集、传输的框架&#xff0c;本文在其基础对埋点信息进行解析&#xff0c;来看下Android 中埋下的内存信息有哪些。 1. 通过代码剖析google 埋点内容 1.1 PROCESS_M…

BootStrap前端面试常见问题

在前端面试中&#xff0c;关于Bootstrap的问题通常围绕其基本概念、使用方式、特性以及实际应用等方面展开。以下是一些常见的问题及其详细解答&#xff1a; 1. Bootstrap是哪家公司研发的&#xff1f; 回答&#xff1a;Bootstrap是由Twitter的Mark Otto和Jacob Thornton合作…

脊髓损伤小伙伴的活力重启秘籍! 让我们一起动起来,拥抱不一样的精彩生活✨

Hey小伙伴们~&#x1f44b; 今天咱们来聊聊一个超级重要又温暖的话题——脊髓损伤后的锻炼大法来啦&#xff01;&#x1f389; 记住&#xff0c;无论遇到什么挑战&#xff0c;我们都要像打不死的小强一样&#xff0c;活力满满地面对每一天&#xff01;&#x1f4aa; 首先&#…

2024实验班选拔考试(热身赛)

比赛传送门 邀请码&#xff1a;2024wksyb A. 简单的数列问题 签到&#xff0c;记得开long long。 #include<bits/stdc.h> #define rep(i,a,b) for (int ia;i<b;i) #define per(i,a,b) for (int ia;i>b;--i) #define se second #define fi first #define endl …

【C#语音文字互转】.NET的TTS文本转语音合成

官方文档给出环境为Visual Studio 2017及以上&#xff1b;C#SDK为.NET4.8及以上 本文章环境介绍&#xff1a; Visual Studio 2022&#xff1b;C#SDK为.NET6.0 语音转文字请移步&#xff1a;【C#语音文字互转】C#语音转文字&#xff08;方法一&#xff09; 一. 启动 Visual Stud…

【OceanBase系列】—— OceanBase应急三板斧

作者&#xff1a; 花名&#xff1a;洪波&#xff0c; OceanBase 数据库解决方案架构师 目前随着OceanBase数据库越来越流行&#xff0c;社区已经有很多用户在生产环境使用了OceanBase&#xff0c;也有不少用户的核心业务用到了OceanBase数据库&#xff0c;在使用OceanBase数据库…

新址·新征程|美创科技北京中心喜迎乔迁

7月30日&#xff0c;北京暴雨倾城 连绵大雨和隆隆雷声 却像是在为一场新征程洗礼 这一天&#xff0c;我们迎来了重要的时刻 ——美创科技北京中心搬新家啦&#xff01; 新址&#xff1a;北京市海淀区庚坊国际大厦6层 喜迎新址&#xff0c;一场简单但喜气盈盈、温馨十足的乔…