wordpress 头像设置,做网络优化哪家公司比较好,股票互动平台,python做网站怎么样AVRational结构体和其相关的函数分析#xff1a;
FFmpeg有理数相关的源码#xff1a;AVRational结构体和其相关的函数分析
FFmpeg源码#xff1a;av_reduce函数分析 一、av_reduce函数的声明
av_reduce函数声明在FFmpeg源码#xff08;本文演示用的FFmpeg源码版本为7.0…
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;
} 输出如下