ffmpeg 中av_rescale_rnd 的含义

ffmpeg 中av_rescale_rnd 的含义

我看了网上若干帖子,包括分析代码的,感觉都说得不是太清晰,所以自己也来说说.

函数声明:
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
它的作用是计算 "a * b / c" 的值

由于其结果不一定能整除,但其结果是一个整数,所以就牵扯一个取整问题,
这里它定义了五种取整方式

enum AVRounding {
    AV_ROUND_ZERO     = 0, ///< Round toward zero.
    AV_ROUND_INF      = 1, ///< Round away from zero.
    AV_ROUND_DOWN     = 2, ///< Round toward -infinity.
    AV_ROUND_UP       = 3, ///< Round toward +infinity.
    AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero.
    AV_ROUND_PASS_MINMAX = 8192, //这个位是个附加位,必需与其它位组合使用,所以算5种模式
};
我们先把英文的翻译成汉文:

AV_ROUND_ZERO ,向0舍入,解释为趋于0,是什么意思?
AV_ROUND_INF ,向无穷舍入,解释为远离0,是什么意思?
AV_ROUND_DOWN, 向下舍入,注释为趋于负无穷
AV_ROUND_UP,  向上舍入,注释为趋于正无穷
AV_ROUND_NEAR_INF 就近无穷, 解释为向最近的方向,1半的化要远离0, 总之就是4舍5入的意思
AV_ROUND_PASS_MINMAX = 8192, //这个位置位时,当a=INT64_MIN或a=INT64_MAX时  a值pass throuth

这么绕, 翻译了也不是太清楚,嗯, 我们从容易理解的地方着手!
我们可以容易理解的是3种:
1. 向上舍入        例如: 123.1 向上舍入为124, 123.9向上舍入为124
2. 向下舍入        例如: 123.1 向下舍入为123, 123.9向下舍入为123
3. 4舍5入,        例如: 123.1 4舍5入为123, 123.9 4舍5入为124, 123.5 舍5入为124

那趋于0舍入,趋于无穷舍入又是什么玩意?


下面看代码, 我没有直接复制,没必要,拣关键的说明问题:
在(libavutil/mathematics.c):58行 (ffmpeg4.4)
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)

1. 当有AV_ROUND_PASS_MINMAX 标志时,如果时INT64_MIN,INT64_MAX, 直接返回a
    if (rnd & AV_ROUND_PASS_MINMAX) {
        if (a == INT64_MIN || a == INT64_MAX)
            return a;
    }

2. 其它核心运算
    r = 0;                            //默认余数为0,实际包含了模式0(AV_ROUND_ZERO),模式2(AV_ROUND_DOWN)
    if (rnd == AV_ROUND_NEAR_INF)    //这是模式5(AV_ROUND_NEAR_INF)
        r = c / 2;                    //当4舍5入时,我们取余数为c/2
    else if (rnd & 1)                //这里包含了模式1(AV_ROUND_INF),模式3(AV_ROUND_UP)
        r = c - 1;                    //当趋于无穷或者UP时,取余数c-1
    return (a * b + r) / c;            // 计算(a*b+余数)/c

    由此我们看到,其实不是五种舍入方式,还是3种舍入方式.
    所谓的趋于0舍入就是下舍入。
    所谓的趋于无穷舍入就是上舍入。
    搞得这么玄幻,何必呢? 可能是历史原因吧.


在FFmpeg中,  一般不直接调用av_rescale_rnd, 而是使用 av_rescale_q_rnd
它的意义是以bq为时基表示的数值a, 表达成以cq为时基的数值, 计算方式为: a*bq/cq
它的声明及代码如下:
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd)
{
    int64_t b = bq.num * (int64_t)cq.den;
    int64_t c = cq.num * (int64_t)bq.den;
    return av_rescale_rnd(a, b, c, rnd);
}

例如:
    常见的视频帧时长3600 是以 90K为时基(1,90000)表示成1M时基(1,1000000)
    3600*(1/90000)/(1/1000000)=3600*100/9=40000 (us) = 40(ms) 等于 25帧/s
    用函数表示:
    av_rescale_rnd(duration,base_90k,base_us);

你可能感兴趣的:(ffmpeg,ffmpeg,round,中av_rescale_rnd)