1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #define MODULE_TAG "mpp_enc_ref"
7
8 #include <string.h>
9
10 #include "mpp_env.h"
11 #include "mpp_log.h"
12 #include "mpp_mem.h"
13 #include "mpp_time.h"
14
15 #include "mpp_rc_defs.h"
16 #include "mpp_enc_ref.h"
17 #include "mpp_enc_refs.h"
18
19 #define setup_mpp_enc_ref_cfg(ref) \
20 ((MppEncRefCfgImpl*)ref)->name = MODULE_TAG;
21
_check_is_mpp_enc_ref_cfg(const char * func,void * ref)22 MPP_RET _check_is_mpp_enc_ref_cfg(const char *func, void *ref)
23 {
24 if (NULL == ref) {
25 mpp_err("%s input ref check NULL failed\n", func);
26 return MPP_NOK;
27 }
28
29 if (strcmp(((MppEncRefCfgImpl*)(ref))->name, MODULE_TAG) != 0) {
30 mpp_err("%s input ref check %p %p failed\n", func, ((MppEncRefCfgImpl*)(ref))->name);
31 return MPP_NOK;
32 }
33
34 return MPP_OK;
35 }
36
mpp_enc_ref_cfg_init(MppEncRefCfg * ref)37 MPP_RET mpp_enc_ref_cfg_init(MppEncRefCfg *ref)
38 {
39 if (NULL == ref) {
40 mpp_err_f("invalid NULL input ref_cfg\n");
41 return MPP_ERR_NULL_PTR;
42 }
43
44 MppEncRefCfgImpl *p = mpp_calloc(MppEncRefCfgImpl, 1);
45 *ref = p;
46 if (NULL == p) {
47 mpp_err_f("malloc failed\n");
48 return MPP_ERR_NULL_PTR;
49 }
50
51 mpp_env_get_u32("enc_ref_cfg_debug", &p->debug, 0);
52
53 setup_mpp_enc_ref_cfg(p);
54
55 return MPP_OK;
56 }
57
mpp_enc_ref_cfg_deinit(MppEncRefCfg * ref)58 MPP_RET mpp_enc_ref_cfg_deinit(MppEncRefCfg *ref)
59 {
60 if (!ref || check_is_mpp_enc_ref_cfg(*ref)) {
61 mpp_err_f("input %p check failed\n", ref);
62 return MPP_ERR_VALUE;
63 }
64
65 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)(*ref);
66 MPP_FREE(p->lt_cfg);
67 MPP_FREE(p->st_cfg);
68 MPP_FREE(p);
69
70 return MPP_OK;
71 }
72
mpp_enc_ref_cfg_reset(MppEncRefCfg ref)73 MPP_RET mpp_enc_ref_cfg_reset(MppEncRefCfg ref)
74 {
75 if (check_is_mpp_enc_ref_cfg(ref))
76 return MPP_ERR_VALUE;
77
78 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
79 MPP_FREE(p->lt_cfg);
80 MPP_FREE(p->st_cfg);
81 memset(p, 0, sizeof(*p));
82 setup_mpp_enc_ref_cfg(p);
83
84 return MPP_OK;
85 }
86
mpp_enc_ref_cfg_set_cfg_cnt(MppEncRefCfg ref,RK_S32 lt_cnt,RK_S32 st_cnt)87 MPP_RET mpp_enc_ref_cfg_set_cfg_cnt(MppEncRefCfg ref, RK_S32 lt_cnt, RK_S32 st_cnt)
88 {
89 if (check_is_mpp_enc_ref_cfg(ref))
90 return MPP_ERR_NULL_PTR;
91
92 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
93 MppEncRefLtFrmCfg *lt_cfg = p->lt_cfg;
94 MppEncRefStFrmCfg *st_cfg = p->st_cfg;;
95
96 if (lt_cfg || st_cfg) {
97 mpp_err_f("do call reset before setup new cnout\n");
98 MPP_FREE(lt_cfg);
99 MPP_FREE(st_cfg);
100 }
101
102 if (lt_cnt) {
103 lt_cfg = mpp_calloc(MppEncRefLtFrmCfg, lt_cnt);
104 if (NULL == lt_cfg)
105 mpp_log_f("failed to create %d lt ref cfg\n", lt_cnt);
106 }
107
108 if (st_cnt) {
109 st_cfg = mpp_calloc(MppEncRefStFrmCfg, st_cnt);
110 if (NULL == st_cfg)
111 mpp_log_f("failed to create %d st ref cfg\n", lt_cnt);
112 }
113
114 p->max_lt_cfg = lt_cnt;
115 p->max_st_cfg = st_cnt;
116 p->lt_cfg_cnt = 0;
117 p->st_cfg_cnt = 0;
118 p->lt_cfg = lt_cfg;
119 p->st_cfg = st_cfg;
120
121 return MPP_OK;
122 }
123
mpp_enc_ref_cfg_add_lt_cfg(MppEncRefCfg ref,RK_S32 cnt,MppEncRefLtFrmCfg * frm)124 MPP_RET mpp_enc_ref_cfg_add_lt_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefLtFrmCfg *frm)
125 {
126 if (check_is_mpp_enc_ref_cfg(ref))
127 return MPP_ERR_VALUE;
128
129 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
130
131 if (p->debug)
132 mpp_log("ref %p add lt %d cfg idx %d tid %d gap %d delay %d ref mode %x\n",
133 ref, p->lt_cfg_cnt, frm->lt_idx, frm->temporal_id,
134 frm->lt_gap, frm->lt_delay, frm->ref_mode);
135
136 memcpy(&p->lt_cfg[p->lt_cfg_cnt], frm, sizeof(*frm) * cnt);
137 p->lt_cfg_cnt += cnt;
138
139 return MPP_OK;
140 }
141
mpp_enc_ref_cfg_add_st_cfg(MppEncRefCfg ref,RK_S32 cnt,MppEncRefStFrmCfg * frm)142 MPP_RET mpp_enc_ref_cfg_add_st_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefStFrmCfg *frm)
143 {
144 if (check_is_mpp_enc_ref_cfg(ref)) {
145 mpp_err_f("input %p check failed\n", ref);
146 return MPP_ERR_VALUE;
147 }
148
149 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
150
151 if (p->debug)
152 mpp_log("ref %p add lt %d cfg non %d tid %d gap repeat %d ref mode %x arg %d\n",
153 ref, p->st_cfg_cnt, frm->is_non_ref, frm->temporal_id,
154 frm->repeat, frm->ref_mode, frm->ref_arg);
155
156 memcpy(&p->st_cfg[p->st_cfg_cnt], frm, sizeof(*frm) * cnt);
157 p->st_cfg_cnt += cnt;
158
159 return MPP_OK;
160 }
161
mpp_enc_ref_cfg_check(MppEncRefCfg ref)162 MPP_RET mpp_enc_ref_cfg_check(MppEncRefCfg ref)
163 {
164 if (check_is_mpp_enc_ref_cfg(ref))
165 return MPP_ERR_VALUE;
166
167 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
168 RK_S32 lt_cfg_cnt = p->lt_cfg_cnt;
169 RK_S32 st_cfg_cnt = p->st_cfg_cnt;
170 RK_S32 max_lt_ref_cnt = 0;
171 RK_S32 max_lt_ref_idx = 0;
172 RK_S32 lt_idx_used_mask = 0;
173 RK_S32 lt_dryrun_length = 0;
174 RK_S32 max_st_ref_cnt = 0;
175 RK_S32 max_st_tid = 0;
176 RK_S32 st_tid_used_mask = 0;
177 RK_S32 st_dryrun_length = 0;
178 RK_S32 ready = 1;
179
180 /* parse and check gop config for encoder */
181 if (lt_cfg_cnt) {
182 RK_S32 pos = 0;
183 MppEncRefLtFrmCfg *cfg = p->lt_cfg;
184
185 for (pos = 0; pos < lt_cfg_cnt; pos++, cfg++) {
186 MppEncRefMode ref_mode = cfg->ref_mode;
187 RK_S32 temporal_id = cfg->temporal_id;
188 RK_S32 lt_idx = cfg->lt_idx;
189 RK_U32 lt_idx_mask = 1 << lt_idx;
190
191 /* check lt idx */
192 if (lt_idx >= MPP_ENC_MAX_LT_REF_NUM) {
193 mpp_err_f("ref cfg %p lt cfg %d with invalid lt_idx %d larger than MPP_ENC_MAX_LT_REF_NUM\n",
194 ref, pos, lt_idx);
195 ready = 0;
196 }
197
198 if (lt_idx_used_mask & lt_idx_mask) {
199 mpp_err_f("ref cfg %p lt cfg %d with redefined lt_idx %d config\n",
200 ref, pos, lt_idx);
201 ready = 0;
202 }
203
204 if (!(lt_idx_used_mask & lt_idx_mask)) {
205 lt_idx_used_mask |= lt_idx_mask;
206 max_lt_ref_cnt++;
207 }
208
209 if (lt_idx > max_lt_ref_idx)
210 max_lt_ref_idx = lt_idx;
211
212 /* check temporal id */
213 if (temporal_id != 0) {
214 mpp_err_f("ref cfg %p lt cfg %d with invalid temporal_id %d is non-zero\n",
215 ref, pos, temporal_id);
216 ready = 0;
217 }
218
219 /* check gop mode */
220 if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_LT_MODE(ref_mode)) {
221 mpp_err_f("ref cfg %p lt cfg %d with invalid ref mode %x\n",
222 ref, pos, ref_mode);
223 ready = 0;
224 }
225
226 /* if check failed just quit */
227 if (!ready)
228 break;
229
230 if (cfg->lt_gap && (cfg->lt_gap + cfg->lt_delay > lt_dryrun_length))
231 lt_dryrun_length = cfg->lt_gap + cfg->lt_delay;
232 }
233 }
234
235 /* check st-ref config */
236 if (ready && st_cfg_cnt) {
237 RK_S32 pos = 0;
238 MppEncRefStFrmCfg *cfg = p->st_cfg;
239
240 for (pos = 0; pos < st_cfg_cnt; pos++, cfg++) {
241 MppEncRefMode ref_mode = cfg->ref_mode;
242 RK_S32 temporal_id = cfg->temporal_id;
243 RK_U32 tid_mask = 1 << temporal_id;
244
245 /* check temporal_id */
246 if (temporal_id > MPP_ENC_MAX_TEMPORAL_LAYER_NUM - 1) {
247 mpp_err_f("ref cfg %p st cfg %d with invalid temporal_id %d larger than MPP_ENC_MAX_TEMPORAL_LAYER_NUM\n",
248 ref, pos, temporal_id);
249 ready = 0;
250 }
251
252 /* check gop mode */
253 if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_ST_MODE(ref_mode)) {
254 mpp_err_f("ref cfg %p st cfg %d with invalid ref mode %x\n",
255 ref, pos, ref_mode);
256 ready = 0;
257 }
258
259 if (cfg->repeat < 0) {
260 mpp_err_f("ref cfg %p st cfg %d with negative repeat %d set to zero\n",
261 ref, pos, cfg->repeat);
262 cfg->repeat = 0;
263 }
264
265 /* constrain on head and tail frame */
266 if (pos == 0 || (pos == st_cfg_cnt - 1)) {
267 if (cfg->is_non_ref) {
268 mpp_err_f("ref cfg %p st cfg %d with invalid non-ref frame on head/tail frame\n",
269 ref, pos);
270 ready = 0;
271 }
272
273 if (temporal_id > 0) {
274 mpp_err_f("ref cfg %p st cfg %d with invalid non-zero temporal id %d on head/tail frame\n",
275 ref, pos, temporal_id);
276 ready = 0;
277 }
278 }
279
280 if (!ready)
281 break;
282
283 if (!cfg->is_non_ref && !(st_tid_used_mask & tid_mask)) {
284 max_st_ref_cnt++;
285 st_tid_used_mask |= tid_mask;
286 }
287
288 if (temporal_id > max_st_tid)
289 max_st_tid = temporal_id;
290
291 st_dryrun_length++;
292 st_dryrun_length += cfg->repeat;
293 }
294 }
295
296 if (ready) {
297 MppEncCpbInfo *cpb_info = &p->cpb_info;
298 MppEncRefs refs = NULL;
299 MPP_RET ret = MPP_OK;
300
301 cpb_info->dpb_size = 0;
302 cpb_info->max_lt_cnt = max_lt_ref_cnt;
303 cpb_info->max_st_cnt = max_st_ref_cnt;
304 cpb_info->max_lt_idx = max_lt_ref_idx;
305 cpb_info->max_st_tid = max_st_tid;
306 cpb_info->lt_gop = lt_dryrun_length;
307 cpb_info->st_gop = st_dryrun_length - 1;
308
309 ret = mpp_enc_refs_init(&refs);
310 ready = (ret) ? 0 : (ready);
311 ret = mpp_enc_refs_set_cfg(refs, ref);
312 ready = (ret) ? 0 : (ready);
313 ret = mpp_enc_refs_dryrun(refs);
314 ready = (ret) ? 0 : (ready);
315
316 /* update dpb size */
317 ret = mpp_enc_refs_get_cpb_info(refs, cpb_info);
318 ready = (ret) ? 0 : (ready);
319
320 ret = mpp_enc_refs_deinit(&refs);
321 ready = (ret) ? 0 : (ready);
322 } else {
323 mpp_err_f("check ref cfg %p failed\n", ref);
324 }
325 p->ready = ready;
326
327 return ready ? MPP_OK : MPP_NOK;
328 }
329
mpp_enc_ref_cfg_set_keep_cpb(MppEncRefCfg ref,RK_S32 keep)330 MPP_RET mpp_enc_ref_cfg_set_keep_cpb(MppEncRefCfg ref, RK_S32 keep)
331 {
332 if (check_is_mpp_enc_ref_cfg(ref))
333 return MPP_ERR_VALUE;
334
335 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
336 p->keep_cpb = keep;
337
338 return MPP_OK;
339 }
340
mpp_enc_ref_cfg_show(MppEncRefCfg ref)341 MPP_RET mpp_enc_ref_cfg_show(MppEncRefCfg ref)
342 {
343 if (check_is_mpp_enc_ref_cfg(ref))
344 return MPP_ERR_VALUE;
345
346 return MPP_OK;
347 }
348
mpp_enc_ref_cfg_copy(MppEncRefCfg dst,MppEncRefCfg src)349 MPP_RET mpp_enc_ref_cfg_copy(MppEncRefCfg dst, MppEncRefCfg src)
350 {
351 if (check_is_mpp_enc_ref_cfg(dst) || check_is_mpp_enc_ref_cfg(src))
352 return MPP_ERR_VALUE;
353
354 MPP_RET ret = MPP_OK;
355 MppEncRefCfgImpl *d = (MppEncRefCfgImpl *)dst;
356 MppEncRefCfgImpl *s = (MppEncRefCfgImpl *)src;
357 RK_S32 max_lt_cfg = s->max_lt_cfg;
358 RK_S32 max_st_cfg = s->max_st_cfg;
359
360 /* step 1 - free cfg in dst */
361 MPP_FREE(d->lt_cfg);
362 MPP_FREE(d->st_cfg);
363
364 /* step 2 - copy contex from src */
365 memcpy(d, s, sizeof(*d));
366
367 /* step 3 - create new storage and copy lt/st cfg */
368 if (max_lt_cfg) {
369 MppEncRefLtFrmCfg *lt_cfg = mpp_calloc(MppEncRefLtFrmCfg, max_lt_cfg);
370
371 if (NULL == lt_cfg) {
372 mpp_log_f("failed to create %d lt ref cfg\n", max_lt_cfg);
373 ret = MPP_NOK;
374 } else
375 memcpy(lt_cfg, s->lt_cfg, sizeof(lt_cfg[0]) * s->max_lt_cfg);
376
377 d->lt_cfg = lt_cfg;
378 }
379
380 if (max_st_cfg) {
381 MppEncRefStFrmCfg *st_cfg = mpp_calloc(MppEncRefStFrmCfg, max_st_cfg);
382
383 if (NULL == st_cfg) {
384 mpp_log_f("failed to create %d st ref cfg\n", max_st_cfg);
385 ret = MPP_NOK;
386 } else
387 memcpy(st_cfg, s->st_cfg, sizeof(st_cfg[0]) * s->max_st_cfg);
388
389 d->st_cfg = st_cfg;
390 }
391
392 if (ret)
393 mpp_enc_ref_cfg_reset(dst);
394
395 return ret;
396 }
397
mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref)398 MppEncCpbInfo *mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref)
399 {
400 if (check_is_mpp_enc_ref_cfg(ref))
401 return NULL;
402
403 MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
404 return &p->cpb_info;
405 }
406
407 static MppEncRefStFrmCfg default_st_ref_cfg = {
408 .is_non_ref = 0,
409 .temporal_id = 0,
410 .ref_mode = REF_TO_PREV_REF_FRM,
411 .ref_arg = 0,
412 .repeat = 0,
413 };
414
415 static const MppEncRefCfgImpl default_ref_cfg = {
416 .name = MODULE_TAG,
417 .ready = 1,
418 .debug = 0,
419 .keep_cpb = 0,
420 .max_lt_cfg = 0,
421 .max_st_cfg = 1,
422 .lt_cfg_cnt = 0,
423 .st_cfg_cnt = 1,
424 .max_tlayers = 1,
425 .lt_cfg = NULL,
426 .st_cfg = &default_st_ref_cfg,
427 .cpb_info = { 1, 0, 1, 0, 0, 0, 0 },
428 };
429
mpp_enc_ref_default(void)430 MppEncRefCfg mpp_enc_ref_default(void)
431 {
432 return (MppEncRefCfg)&default_ref_cfg;
433 }
434