mirror of
https://github.com/nyanmisaka/mpp.git
synced 2025-10-05 09:06:50 +08:00

Change-Id: Ie85b780076b22342bfc1837beef00036f5f40a04 Signed-off-by: Herman Chen <herman.chen@rock-chips.com> Signed-off-by: timkingh.huang <timkingh.huang@rock-chips.com>
627 lines
16 KiB
C++
627 lines
16 KiB
C++
/*
|
|
* Copyright 2016 Rockchip Electronics Co. LTD
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define MODULE_TAG "mpp_rc"
|
|
|
|
#include "mpp_env.h"
|
|
#include "mpp_mem.h"
|
|
#include "mpp_common.h"
|
|
#include "mpp_rc.h"
|
|
|
|
#define MPP_RC_DBG_FUNCTION (0x00000001)
|
|
#define MPP_RC_DBG_RC (0x00000010)
|
|
#define MPP_RC_DBG_CFG (0x00000100)
|
|
|
|
#define mpp_rc_dbg(flag, fmt, ...) _mpp_dbg(mpp_rc_debug, flag, fmt, ## __VA_ARGS__)
|
|
#define mpp_rc_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_rc_debug, flag, fmt, ## __VA_ARGS__)
|
|
|
|
#define mpp_rc_dbg_func(fmt, ...) mpp_rc_dbg_f(MPP_RC_DBG_FUNCTION, fmt, ## __VA_ARGS__)
|
|
#define mpp_rc_dbg_rc(fmt, ...) mpp_rc_dbg(MPP_RC_DBG_RC, fmt, ## __VA_ARGS__)
|
|
#define mpp_rc_dbg_cfg(fmt, ...) mpp_rc_dbg(MPP_RC_DBG_CFG, fmt, ## __VA_ARGS__)
|
|
|
|
#define SIGN(a) ((a) < (0) ? (-1) : (1))
|
|
#define DIV(a, b) (((a) + (SIGN(a) * (b)) / 2) / (b))
|
|
|
|
static RK_U32 mpp_rc_debug = 0;
|
|
|
|
static RK_S32 axb_div_c(RK_S32 a, RK_S32 b, RK_S32 c)
|
|
{
|
|
RK_U32 left = 32;
|
|
RK_U32 right = 0;
|
|
RK_U32 shift;
|
|
RK_S32 sign = 1;
|
|
RK_S32 tmp;
|
|
|
|
if (a == 0 || b == 0)
|
|
return 0;
|
|
else if ((a * b / b) == a && c != 0)
|
|
return (a * b / c);
|
|
|
|
if (a < 0) {
|
|
sign = -1;
|
|
a = -a;
|
|
}
|
|
if (b < 0) {
|
|
sign *= -1;
|
|
b = -b;
|
|
}
|
|
if (c < 0) {
|
|
sign *= -1;
|
|
c = -c;
|
|
}
|
|
|
|
if (c == 0)
|
|
return 0x7FFFFFFF * sign;
|
|
|
|
if (b > a) {
|
|
tmp = b;
|
|
b = a;
|
|
a = tmp;
|
|
}
|
|
|
|
for (--left; (((RK_U32)a << left) >> left) != (RK_U32)a; --left)
|
|
;
|
|
|
|
left--;
|
|
|
|
while (((RK_U32)b >> right) > (RK_U32)c)
|
|
right++;
|
|
|
|
if (right > left) {
|
|
return 0x7FFFFFFF * sign;
|
|
} else {
|
|
shift = left - right;
|
|
return (RK_S32)((((RK_U32)a << shift) /
|
|
(RK_U32)c * (RK_U32)b) >> shift) * sign;
|
|
}
|
|
}
|
|
|
|
MPP_RET mpp_data_init(MppData **data, RK_S32 size)
|
|
{
|
|
if (NULL == data || size <= 0) {
|
|
mpp_err_f("invalid data %data size %d\n", data, size);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
*data = NULL;
|
|
MppData *p = mpp_malloc_size(MppData, sizeof(MppData) + sizeof(RK_S32) * size);
|
|
if (NULL == p) {
|
|
mpp_err_f("malloc size %d failed\n", size);
|
|
return MPP_ERR_MALLOC;
|
|
}
|
|
p->size = size;
|
|
p->len = 0;
|
|
p->pos = 0;
|
|
p->val = (RK_S32 *)(p + 1);
|
|
*data = p;
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
void mpp_data_deinit(MppData *p)
|
|
{
|
|
if (p)
|
|
mpp_free(p);
|
|
}
|
|
|
|
void mpp_data_update(MppData *p, RK_S32 val)
|
|
{
|
|
mpp_assert(p);
|
|
|
|
p->val[p->pos] = val;
|
|
|
|
if (++p->pos >= p->size)
|
|
p->pos = 0;
|
|
|
|
if (p->len < p->size)
|
|
p->len++;
|
|
}
|
|
|
|
RK_S32 mpp_data_avg(MppData *p, RK_S32 len, RK_S32 num, RK_S32 denorm)
|
|
{
|
|
mpp_assert(p);
|
|
|
|
RK_S32 i;
|
|
RK_S32 sum = 0;
|
|
RK_S32 pos = p->pos;
|
|
|
|
if (!p->len)
|
|
return 0;
|
|
|
|
if (len < 0 || len > p->len)
|
|
len = p->len;
|
|
|
|
if (num == denorm) {
|
|
i = len;
|
|
while (i--) {
|
|
if (pos)
|
|
pos--;
|
|
else
|
|
pos = p->len - 1;
|
|
|
|
sum += p->val[pos];
|
|
}
|
|
} else {
|
|
mpp_assert(num > denorm);
|
|
RK_S32 acc_num = num;
|
|
RK_S32 acc_denorm = denorm;
|
|
|
|
i = len - 1;
|
|
sum = p->val[--pos];
|
|
while (i--) {
|
|
if (pos)
|
|
pos--;
|
|
else
|
|
pos = p->len - 1;
|
|
|
|
sum += p->val[pos] * acc_num / acc_denorm;
|
|
acc_num += num;
|
|
acc_denorm += denorm;
|
|
}
|
|
}
|
|
return DIV(sum, len);
|
|
}
|
|
|
|
void mpp_pid_reset(MppPIDCtx *p)
|
|
{
|
|
p->p = 0;
|
|
p->i = 0;
|
|
p->d = 0;
|
|
p->count = 0;
|
|
}
|
|
|
|
void mpp_pid_set_param(MppPIDCtx *ctx, RK_S32 coef_p, RK_S32 coef_i, RK_S32 coef_d, RK_S32 div, RK_S32 len)
|
|
{
|
|
ctx->coef_p = coef_p;
|
|
ctx->coef_i = coef_i;
|
|
ctx->coef_d = coef_d;
|
|
ctx->div = div;
|
|
ctx->len = len;
|
|
ctx->count = 0;
|
|
|
|
mpp_rc_dbg_rc("RC: pid ctx %p coef: P %d I %d D %d div %d len %d\n",
|
|
ctx, coef_p, coef_i, coef_d, div, len);
|
|
}
|
|
|
|
void mpp_pid_update(MppPIDCtx *ctx, RK_S32 val)
|
|
{
|
|
mpp_rc_dbg_rc("RC: pid ctx %p update val %d\n", ctx, val);
|
|
mpp_rc_dbg_rc("RC: pid ctx %p before update P %d I %d D %d\n", ctx, ctx->p, ctx->i, ctx->d);
|
|
|
|
ctx->d = val - ctx->p; /* Derivative */
|
|
ctx->i = val + ctx->i; /* Integral */
|
|
ctx->p = val; /* Proportional */
|
|
|
|
mpp_rc_dbg_rc("RC: pid ctx %p after update P %d I %d D %d\n", ctx, ctx->p, ctx->i, ctx->d);
|
|
ctx->count++;
|
|
/*
|
|
* pid control is a short time control, it needs periodically reset
|
|
*/
|
|
if (ctx->count >= ctx->len)
|
|
mpp_pid_reset(ctx);
|
|
}
|
|
|
|
RK_S32 mpp_pid_calc(MppPIDCtx *p)
|
|
{
|
|
RK_S32 a = p->p * p->coef_p + p->i * p->coef_i + p->d * p->coef_d;
|
|
RK_S32 b = p->div;
|
|
|
|
mpp_rc_dbg_rc("RC: pid ctx %p p %10d coef %d\n", p, p->p, p->coef_p);
|
|
mpp_rc_dbg_rc("RC: pid ctx %p i %10d coef %d\n", p, p->i, p->coef_i);
|
|
mpp_rc_dbg_rc("RC: pid ctx %p d %10d coef %d\n", p, p->d, p->coef_d);
|
|
mpp_rc_dbg_rc("RC: pid ctx %p a %10d b %d\n", p, a, b);
|
|
|
|
return DIV(a, b);
|
|
}
|
|
|
|
MPP_RET mpp_rc_init(MppRateControl **ctx)
|
|
{
|
|
if (NULL == ctx) {
|
|
mpp_log_f("invalid ctx %p\n", ctx);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
MPP_RET ret = MPP_OK;
|
|
MppRateControl *p = mpp_calloc(MppRateControl, 1);
|
|
if (NULL == ctx) {
|
|
mpp_log_f("malloc failed\n");
|
|
ret = MPP_ERR_MALLOC;
|
|
} else {
|
|
p->gop = -1;
|
|
}
|
|
|
|
mpp_env_get_u32("mpp_rc_debug", &mpp_rc_debug, 0);
|
|
|
|
*ctx = p;
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET mpp_rc_deinit(MppRateControl *ctx)
|
|
{
|
|
if (NULL == ctx) {
|
|
mpp_log_f("invalid ctx %p\n", ctx);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
if (ctx->intra) {
|
|
mpp_data_deinit(ctx->intra);
|
|
ctx->intra = NULL;
|
|
}
|
|
|
|
if (ctx->gop_bits) {
|
|
mpp_data_deinit(ctx->gop_bits);
|
|
ctx->gop_bits = NULL;
|
|
}
|
|
|
|
mpp_free(ctx);
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET mpp_rc_update_user_cfg(MppRateControl *ctx, MppEncRcCfg *cfg)
|
|
{
|
|
if (NULL == ctx || NULL == cfg) {
|
|
mpp_log_f("invalid ctx %p cfg %p\n", ctx, cfg);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_U32 change = cfg->change;
|
|
RK_U32 clear_acc = 0;
|
|
RK_U32 gop_start = 0;
|
|
|
|
/*
|
|
* step 1: update parameters
|
|
*/
|
|
if (change & MPP_ENC_RC_CFG_CHANGE_BPS) {
|
|
mpp_rc_dbg_cfg("bps: %d [%d %d]\n", cfg->bps_target,
|
|
cfg->bps_min, cfg->bps_max);
|
|
ctx->bps_min = cfg->bps_min;
|
|
ctx->bps_max = cfg->bps_max;
|
|
ctx->bps_target = cfg->bps_target;
|
|
}
|
|
|
|
if (change & MPP_ENC_RC_CFG_CHANGE_FPS_OUT) {
|
|
mpp_rc_dbg_cfg("fps: %d / %d\n", cfg->fps_out_num, cfg->fps_out_denorm);
|
|
ctx->fps_num = cfg->fps_out_num;
|
|
ctx->fps_denom = cfg->fps_out_denorm;
|
|
ctx->fps_out = ctx->fps_num / ctx->fps_denom;
|
|
clear_acc = 1;
|
|
}
|
|
|
|
if ((change & MPP_ENC_RC_CFG_CHANGE_GOP) &&
|
|
(ctx->gop != cfg->gop)) {
|
|
RK_S32 gop = cfg->gop;
|
|
|
|
mpp_rc_dbg_cfg("gop: %d\n", cfg->gop);
|
|
|
|
if (ctx->intra)
|
|
mpp_data_deinit(ctx->intra);
|
|
mpp_data_init(&ctx->intra, gop);
|
|
|
|
if (ctx->gop_bits)
|
|
mpp_data_deinit(ctx->gop_bits);
|
|
mpp_data_init(&ctx->gop_bits, gop);
|
|
|
|
ctx->gop = gop;
|
|
if (gop < ctx->fps_out)
|
|
ctx->window_len = ctx->fps_out;
|
|
else
|
|
ctx->window_len = gop;
|
|
|
|
if (ctx->window_len < 10)
|
|
ctx->window_len = 10;
|
|
|
|
if (ctx->window_len > ctx->fps_out)
|
|
ctx->window_len = ctx->fps_out;
|
|
|
|
mpp_pid_reset(&ctx->pid_intra);
|
|
mpp_pid_reset(&ctx->pid_inter);
|
|
mpp_pid_set_param(&ctx->pid_intra, 4, 6, 0, 100, ctx->window_len);
|
|
mpp_pid_set_param(&ctx->pid_inter, 4, 6, 0, 100, ctx->window_len);
|
|
|
|
clear_acc = 1;
|
|
|
|
/* if gop cfg changed, current frame is regarded as IDR frame */
|
|
gop_start = 1;
|
|
}
|
|
|
|
/*
|
|
* step 2: derivate parameters
|
|
*/
|
|
ctx->bits_per_pic = axb_div_c(cfg->bps_target, ctx->fps_denom, ctx->fps_num);
|
|
mpp_rc_dbg_rc("RC: rc ctx %p target bit per picture %d\n", ctx, ctx->bits_per_pic);
|
|
|
|
if (clear_acc) {
|
|
ctx->acc_intra_bits = 0;
|
|
ctx->acc_inter_bits = 0;
|
|
ctx->acc_total_bits = 0;
|
|
ctx->acc_intra_count = 0;
|
|
ctx->acc_inter_count = 0;
|
|
}
|
|
|
|
RK_S32 gop = ctx->gop;
|
|
RK_S32 avg = ctx->bits_per_pic;
|
|
|
|
ctx->cur_frmtype = INTER_P_FRAME;
|
|
if (gop == 0) {
|
|
/* only one intra then all inter */
|
|
ctx->gop_mode = MPP_GOP_ALL_INTER;
|
|
ctx->bits_per_inter = avg;
|
|
ctx->bits_per_intra = avg * 10;
|
|
ctx->intra_to_inter_rate = 0;
|
|
} else if (gop == 1) {
|
|
/* all intra */
|
|
ctx->gop_mode = MPP_GOP_ALL_INTRA;
|
|
ctx->bits_per_inter = 0;
|
|
ctx->bits_per_intra = avg;
|
|
ctx->intra_to_inter_rate = 0;
|
|
gop_start = 1;
|
|
} else if (ctx->gop < ctx->window_len) {
|
|
/* small gop - use fix allocation */
|
|
ctx->gop_mode = MPP_GOP_SMALL;
|
|
ctx->intra_to_inter_rate = gop + 1;
|
|
ctx->bits_per_inter = avg / 2;
|
|
ctx->bits_per_intra = ctx->bits_per_inter * ctx->intra_to_inter_rate;
|
|
} else {
|
|
/* large gop - use dynamic allocation */
|
|
ctx->gop_mode = MPP_GOP_LARGE;
|
|
ctx->intra_to_inter_rate = 10;
|
|
ctx->bits_per_inter = ctx->bits_per_pic;
|
|
ctx->bits_per_intra = ctx->bits_per_inter * ctx->intra_to_inter_rate;
|
|
}
|
|
|
|
if (ctx->acc_total_count == gop)
|
|
gop_start = 1;
|
|
|
|
if (gop_start) {
|
|
ctx->cur_frmtype = INTRA_FRAME;
|
|
ctx->acc_total_count = 0;
|
|
}
|
|
|
|
cfg->change = 0;
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET mpp_rc_bits_allocation(MppRateControl *ctx, RcSyntax *rc_syn)
|
|
{
|
|
if (NULL == ctx || NULL == rc_syn) {
|
|
mpp_log_f("invalid ctx %p rc_syn %p\n", ctx, rc_syn);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
/* step 1: calc target frame bits */
|
|
switch (ctx->gop_mode) {
|
|
case MPP_GOP_ALL_INTER : {
|
|
if (ctx->cur_frmtype == INTRA_FRAME)
|
|
ctx->bits_target = ctx->bits_per_intra;
|
|
else
|
|
ctx->bits_target = ctx->bits_per_inter - mpp_pid_calc(&ctx->pid_inter);
|
|
} break;
|
|
case MPP_GOP_ALL_INTRA : {
|
|
ctx->bits_target = ctx->bits_per_intra - mpp_pid_calc(&ctx->pid_intra);
|
|
} break;
|
|
default : {
|
|
if (ctx->cur_frmtype == INTRA_FRAME) {
|
|
ctx->bits_target = ctx->bits_per_intra - mpp_pid_calc(&ctx->pid_intra);
|
|
} else {
|
|
if (ctx->pre_frmtype == INTRA_FRAME) {
|
|
/*
|
|
* case - inter frame after intra frame
|
|
* update inter target bits with compensation of previous intra frame
|
|
*/
|
|
RK_S32 bits_prev_intra = mpp_data_avg(ctx->intra, 1, 1, 1);
|
|
ctx->bits_per_inter = ctx->bits_per_pic - (bits_prev_intra - ctx->bits_per_pic) /
|
|
(ctx->window_len - 1);
|
|
mpp_rc_dbg_rc("RC: rc ctx %p bits pic %d win %d intra %d inter %d\n",
|
|
ctx, ctx->bits_per_pic, ctx->window_len,
|
|
bits_prev_intra, ctx->bits_per_inter);
|
|
|
|
mpp_rc_dbg_rc("RC: rc ctx %p update inter target bits to %d\n",
|
|
ctx, ctx->bits_per_inter);
|
|
ctx->bits_target = ctx->bits_per_inter;
|
|
} else {
|
|
RK_S32 diff_bit = mpp_pid_calc(&ctx->pid_inter);
|
|
ctx->bits_target = ctx->bits_per_inter - diff_bit;
|
|
mpp_rc_dbg_rc("RC: rc ctx %p inter pid diff %d target %d\n",
|
|
ctx, diff_bit, ctx->bits_target);
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
|
|
rc_syn->bit_target = ctx->bits_target;
|
|
rc_syn->type = ctx->cur_frmtype;
|
|
if (ctx->cur_frmtype == INTRA_FRAME) {
|
|
mpp_rc_dbg_rc("RC: rc ctx %p intra target bits %d\n", ctx, ctx->bits_target);
|
|
} else {
|
|
mpp_rc_dbg_rc("RC: rc ctx %p inter target bits %d\n", ctx, ctx->bits_target);
|
|
}
|
|
|
|
/* step 2: calc min and max bits */
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET mpp_rc_update_hw_result(MppRateControl *ctx, RcHalResult *result)
|
|
{
|
|
if (NULL == ctx || NULL == result) {
|
|
mpp_log_f("invalid ctx %p result %p\n", ctx, result);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
RK_S32 bits = result->bits;
|
|
|
|
if (result->type == INTRA_FRAME) {
|
|
mpp_rc_dbg_rc("RC: rc ctx %p intra real bits %d target %d\n",
|
|
ctx, bits, ctx->bits_per_intra);
|
|
ctx->acc_intra_count++;
|
|
ctx->acc_intra_bits += bits;
|
|
mpp_data_update(ctx->intra, bits);
|
|
mpp_data_update(ctx->gop_bits, bits);
|
|
mpp_pid_update(&ctx->pid_intra, bits - ctx->bits_per_intra);
|
|
} else {
|
|
mpp_rc_dbg_rc("RC: rc ctx %p inter real bits %d target %d\n",
|
|
ctx, bits, ctx->bits_per_inter);
|
|
ctx->acc_inter_count++;
|
|
ctx->acc_inter_bits += bits;
|
|
mpp_data_update(ctx->gop_bits, bits);
|
|
mpp_pid_update(&ctx->pid_inter, bits - ctx->bits_per_inter);
|
|
}
|
|
ctx->acc_total_count++;
|
|
|
|
switch (ctx->gop_mode) {
|
|
case MPP_GOP_ALL_INTER : {
|
|
} break;
|
|
case MPP_GOP_ALL_INTRA : {
|
|
} break;
|
|
default : {
|
|
} break;
|
|
}
|
|
|
|
ctx->pre_frmtype = ctx->cur_frmtype;
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET mpp_linreg_init(MppLinReg **ctx, RK_S32 size)
|
|
{
|
|
if (NULL == ctx) {
|
|
mpp_log_f("invalid ctx %p\n", ctx);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
MPP_RET ret = MPP_OK;
|
|
MppLinReg *p = mpp_calloc_size(MppLinReg,
|
|
sizeof(MppLinReg) +
|
|
size * (sizeof(RK_S32) * 2 + sizeof(RK_S64)));
|
|
if (NULL == p) {
|
|
mpp_log_f("malloc failed\n");
|
|
ret = MPP_ERR_MALLOC;
|
|
} else {
|
|
p->x = (RK_S32 *)(p + 1);
|
|
p->r = p->x + size;
|
|
p->y = (RK_S64 *)(p->r + size);
|
|
p->size = size;
|
|
}
|
|
|
|
*ctx = p;
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET mpp_linreg_deinit(MppLinReg *ctx)
|
|
{
|
|
if (NULL == ctx) {
|
|
mpp_log_f("invalid ctx %p\n", ctx);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
mpp_free(ctx);
|
|
return MPP_OK;
|
|
}
|
|
|
|
/*
|
|
* This function want to calculate coefficient 'b' 'a' using ordinary
|
|
* least square.
|
|
* y = b * x + a
|
|
* b_n = accumulate(x * y) - n * (average(x) * average(y))
|
|
* a_n = accumulate(x * x) * accumulate(y) - accumulate(x) * accumulate(x * y)
|
|
* denom = accumulate(x * x) - n * (square(average(x))
|
|
* b = b_n / denom
|
|
* a = a_n / denom
|
|
*/
|
|
MPP_RET mpp_linreg_update(MppLinReg *ctx, RK_S32 x, RK_S32 r)
|
|
{
|
|
if (NULL == ctx) {
|
|
mpp_log_f("invalid ctx %p\n", ctx);
|
|
return MPP_ERR_NULL_PTR;
|
|
}
|
|
|
|
/* step 1: save data */
|
|
ctx->x[ctx->i] = x;
|
|
ctx->r[ctx->i] = r;
|
|
ctx->y[ctx->i] = x * x * r;
|
|
|
|
mpp_rc_dbg_rc("RC: linreg %p save index %d x %d r %d x*x*r %lld\n",
|
|
ctx, ctx->i, x, r, (RK_S64)(x * x * r));
|
|
|
|
if (++ctx->i >= ctx->size)
|
|
ctx->i = 0;
|
|
|
|
if (ctx->n < ctx->size)
|
|
ctx->n++;
|
|
|
|
/* step 2: update coefficient */
|
|
RK_S32 i = 0;
|
|
RK_S32 n;
|
|
RK_S64 acc_xy = 0;
|
|
RK_S64 acc_x = 0;
|
|
RK_S64 acc_y = 0;
|
|
RK_S64 acc_sq_x = 0;
|
|
|
|
RK_S64 b_num = 0;
|
|
RK_S64 denom = 0;
|
|
|
|
RK_S32 *cx = ctx->x;
|
|
RK_S64 *cy = ctx->y;
|
|
|
|
n = ctx->n;
|
|
i = ctx->i;
|
|
|
|
while (n--) {
|
|
if (i == 0)
|
|
i = ctx->size - 1;
|
|
else
|
|
i--;
|
|
|
|
acc_xy += cx[i] * cy[i];
|
|
acc_x += cx[i];
|
|
acc_y += cy[i];
|
|
acc_sq_x += cx[i] * cx[i];
|
|
}
|
|
|
|
b_num = n * acc_xy - acc_x * acc_y;
|
|
denom = n * acc_sq_x - acc_x * acc_x;
|
|
|
|
mpp_rc_dbg_rc("RC: linreg %p acc_xy %lld acc_x %lld acc_y %lld acc_sq_x %lld\n",
|
|
ctx, acc_xy, acc_x, acc_y, acc_sq_x);
|
|
mpp_rc_dbg_rc("RC: linreg %p n %d b_num %lld denom %lld\n",
|
|
ctx, n, b_num, denom);
|
|
|
|
mpp_rc_dbg_rc("RC: linreg %p before update coefficient a %d b %d\n",
|
|
ctx, ctx->a, ctx->b);
|
|
|
|
if (denom)
|
|
ctx->b = DIV(b_num, denom);
|
|
else
|
|
ctx->b = 0;
|
|
|
|
ctx->a = DIV(acc_y, n) - DIV(acc_x * ctx->b, n);
|
|
|
|
mpp_rc_dbg_rc("RC: linreg %p after update coefficient a %d b %d\n",
|
|
ctx, ctx->a, ctx->b);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
RK_S32 mpp_linreg_calc(MppLinReg *ctx, RK_S32 x)
|
|
{
|
|
if (x <= 0)
|
|
return -1;
|
|
|
|
return DIV(ctx->b, x) + DIV(ctx->a, x * x);
|
|
}
|
|
|