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