xref: /rockchip-linux_mpp/mpp/codec/mpp_rc.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3  * Copyright (c) 2016 Rockchip Electronics Co., Ltd.
4  */
5 
6 #define MODULE_TAG "mpp_rc"
7 
8 #include <math.h>
9 #include <memory.h>
10 
11 #include "mpp_env.h"
12 #include "mpp_mem.h"
13 #include "mpp_debug.h"
14 #include "mpp_common.h"
15 #include "mpp_rc.h"
16 
17 #define MPP_RC_DBG_FUNCTION          (0x00000001)
18 #define MPP_RC_DBG_BPS               (0x00000010)
19 #define MPP_RC_DBG_RC                (0x00000020)
20 #define MPP_RC_DBG_CFG               (0x00000100)
21 #define MPP_RC_DBG_RECORD            (0x00001000)
22 #define MPP_RC_DBG_VBV               (0x00002000)
23 
24 
25 #define mpp_rc_dbg(flag, fmt, ...)   _mpp_dbg(mpp_rc_debug, flag, fmt, ## __VA_ARGS__)
26 #define mpp_rc_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_rc_debug, flag, fmt, ## __VA_ARGS__)
27 
28 #define mpp_rc_dbg_func(fmt, ...)    mpp_rc_dbg_f(MPP_RC_DBG_FUNCTION, fmt, ## __VA_ARGS__)
29 #define mpp_rc_dbg_bps(fmt, ...)     mpp_rc_dbg(MPP_RC_DBG_BPS, fmt, ## __VA_ARGS__)
30 #define mpp_rc_dbg_rc(fmt, ...)      mpp_rc_dbg(MPP_RC_DBG_RC, fmt, ## __VA_ARGS__)
31 #define mpp_rc_dbg_cfg(fmt, ...)     mpp_rc_dbg(MPP_RC_DBG_CFG, fmt, ## __VA_ARGS__)
32 #define mpp_rc_dbg_vbv(fmt, ...)     mpp_rc_dbg(MPP_RC_DBG_VBV, fmt, ## __VA_ARGS__)
33 
34 
35 #define SIGN(a)         ((a) < (0) ? (-1) : (1))
36 #define DIV(a, b)       (((a) + (SIGN(a) * (b)) / 2) / (b))
37 
38 static RK_U32 mpp_rc_debug = 0;
39 
mpp_data_init(MppData ** data,RK_S32 size)40 MPP_RET mpp_data_init(MppData **data, RK_S32 size)
41 {
42     if (NULL == data || size <= 0) {
43         mpp_err_f("invalid data %p size %d\n", data, size);
44         return MPP_ERR_NULL_PTR;
45     }
46 
47     *data = NULL;
48     MppData *p = mpp_malloc_size(MppData, sizeof(MppData) + sizeof(RK_S32) * size);
49     if (NULL == p) {
50         mpp_err_f("malloc size %d failed\n", size);
51         return MPP_ERR_MALLOC;
52     }
53     p->size = size;
54     p->len = 0;
55     p->pos = 0;
56     p->val = (RK_S32 *)(p + 1);
57     *data = p;
58 
59     return MPP_OK;
60 }
61 
mpp_data_deinit(MppData * p)62 void mpp_data_deinit(MppData *p)
63 {
64     if (p)
65         mpp_free(p);
66 }
67 
mpp_data_update(MppData * p,RK_S32 val)68 void mpp_data_update(MppData *p, RK_S32 val)
69 {
70     mpp_assert(p);
71 
72     p->val[p->pos] = val;
73 
74     if (++p->pos >= p->size)
75         p->pos = 0;
76 
77     if (p->len < p->size)
78         p->len++;
79 }
80 
mpp_data_avg(MppData * p,RK_S32 len,RK_S32 num,RK_S32 denom)81 RK_S32 mpp_data_avg(MppData *p, RK_S32 len, RK_S32 num, RK_S32 denom)
82 {
83     mpp_assert(p);
84 
85     RK_S32 i;
86     RK_S32 sum = 0;
87     RK_S32 pos = p->pos;
88 
89     if (!p->len)
90         return 0;
91 
92     if (len < 0 || len > p->len)
93         len = p->len;
94 
95     if (num == denom) {
96         i = len;
97         while (i--) {
98             if (pos)
99                 pos--;
100             else
101                 pos = p->len - 1;
102 
103             sum += p->val[pos];
104         }
105     } else {
106         /* This case is not used so far, but may be useful in the future */
107         mpp_assert(num > denom);
108         RK_S32 acc_num = num;
109         RK_S32 acc_denom = denom;
110 
111         i = len - 1;
112         sum = p->val[--pos];
113         while (i--) {
114             if (pos)
115                 pos--;
116             else
117                 pos = p->len - 1;
118 
119             sum += p->val[pos] * acc_num / acc_denom;
120             acc_num *= num;
121             acc_denom *= denom;
122         }
123     }
124     return DIV(sum, len);
125 }
126 
mpp_pid_reset(MppPIDCtx * p)127 void mpp_pid_reset(MppPIDCtx *p)
128 {
129     p->p = 0;
130     p->i = 0;
131     p->d = 0;
132     p->count = 0;
133 }
134 
mpp_pid_set_param(MppPIDCtx * ctx,RK_S32 coef_p,RK_S32 coef_i,RK_S32 coef_d,RK_S32 div,RK_S32 len)135 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)
136 {
137     ctx->coef_p = coef_p;
138     ctx->coef_i = coef_i;
139     ctx->coef_d = coef_d;
140     ctx->div = div;
141     ctx->len = len;
142     ctx->count = 0;
143 
144     mpp_rc_dbg_rc("RC: pid ctx %p coef: P %d I %d D %d div %d len %d\n",
145                   ctx, coef_p, coef_i, coef_d, div, len);
146 }
147 
mpp_pid_update(MppPIDCtx * ctx,RK_S32 val,RK_S32 is_reset)148 void mpp_pid_update(MppPIDCtx *ctx, RK_S32 val, RK_S32 is_reset)
149 {
150     mpp_rc_dbg_rc("RC: pid ctx %p update val %d\n", ctx, val);
151     mpp_rc_dbg_rc("RC: pid ctx %p before update P %d I %d D %d\n", ctx, ctx->p, ctx->i, ctx->d);
152 
153     ctx->d = val - ctx->p;      /* Derivative */
154     ctx->i = val + ctx->i;      /* Integral */
155     ctx->p = val;               /* Proportional */
156 
157     mpp_rc_dbg_rc("RC: pid ctx %p after  update P %d I %d D %d\n", ctx, ctx->p, ctx->i, ctx->d);
158     ctx->count++;
159     /*
160      * pid control is a short time control, it needs periodically reset
161      */
162     if (is_reset && ctx->count >= ctx->len)
163         mpp_pid_reset(ctx);
164 }
165 
mpp_pid_calc(MppPIDCtx * p)166 RK_S32 mpp_pid_calc(MppPIDCtx *p)
167 {
168     RK_S32 a = p->p * p->coef_p + p->i * p->coef_i + p->d * p->coef_d;
169     RK_S32 b = p->div;
170 
171     mpp_rc_dbg_rc("RC: pid ctx %p p %10d coef %d\n", p, p->p, p->coef_p);
172     mpp_rc_dbg_rc("RC: pid ctx %p i %10d coef %d\n", p, p->i, p->coef_i);
173     mpp_rc_dbg_rc("RC: pid ctx %p d %10d coef %d\n", p, p->d, p->coef_d);
174     mpp_rc_dbg_rc("RC: pid ctx %p a %10d b %d\n", p, a, b);
175 
176     return DIV(a, b);
177 }
178 
mpp_rc_param_ops(struct list_head * head,RK_U32 frm_cnt,RC_PARAM_OPS ops,void * arg)179 MPP_RET mpp_rc_param_ops(struct list_head *head, RK_U32 frm_cnt,
180                          RC_PARAM_OPS ops, void *arg)
181 {
182     MPP_RET ret = MPP_OK;
183 
184     if (mpp_rc_debug & MPP_RC_DBG_RECORD) {
185         RecordNode *pos, *n;
186         RK_U32 found_match = 0;
187 
188         list_for_each_entry_safe(pos, n, head, RecordNode, list) {
189             if (frm_cnt == pos->frm_cnt) {
190                 found_match = 1;
191                 break;
192             }
193         }
194 
195         if (!found_match) {
196             mpp_err("frame %d is not found in list_head %p!\n", frm_cnt, head);
197             ret = MPP_NOK;
198         } else {
199             switch (ops) {
200             case RC_RECORD_REAL_BITS : {
201                 pos->real_bits = *((RK_U32*)arg);
202             } break;
203             case RC_RECORD_QP_SUM : {
204                 pos->qp_sum = *((RK_S32*)arg);
205             } break;
206             case RC_RECORD_QP_MIN : {
207                 pos->qp_min = *((RK_S32*)arg);
208             } break;
209             case RC_RECORD_QP_MAX : {
210                 pos->qp_max = *((RK_S32*)arg);
211             } break;
212             case RC_RECORD_WIN_LEN : {
213                 pos->wlen = *((RK_S32*)arg);
214             } break;
215             case RC_RECORD_SET_QP : {
216                 pos->set_qp = *((RK_S32*)arg);
217             } break;
218             case RC_RECORD_REAL_QP : {
219                 pos->real_qp = *((RK_S32*)arg);
220             } break;
221             case RC_RECORD_SSE_SUM : {
222                 pos->sse_sum = *((RK_S64*)arg);
223             } break;
224             default : {
225                 mpp_err("frame %d found invalid operation code %d\n", frm_cnt, ops);
226                 ret = MPP_NOK;
227             }
228             }
229         }
230     }
231 
232     return ret;
233 }
234 
235 
236