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_refs"
7
8 #include <string.h>
9
10 #include "mpp_env.h"
11 #include "mpp_mem.h"
12 #include "mpp_debug.h"
13 #include "mpp_common.h"
14
15 #include "mpp_enc_ref.h"
16 #include "mpp_enc_refs.h"
17
18 #define MAX_CPB_ST_FRM 16
19 #define MAX_CPB_LT_FRM 16
20 #define MAX_CPB_TID_FRM 16
21 #define MAX_CPB_LT_IDX 16
22 #define MAX_CPB_FRM ((MAX_CPB_ST_FRM) + (MAX_CPB_LT_FRM))
23
24 #define MPP_ENC_REFS_DBG_FUNC (0x00000001)
25 #define MPP_ENC_REFS_DBG_FLOW (0x00000002)
26 #define MPP_ENC_REFS_DBG_FRM (0x00000004)
27 #define MPP_ENC_REFS_DBG_SIZE (0x00000008)
28
29 #define enc_refs_dbg_func(fmt, ...) _mpp_dbg_f(enc_refs_debug, MPP_ENC_REFS_DBG_FUNC, fmt, ## __VA_ARGS__)
30 #define enc_refs_dbg_flow(fmt, ...) _mpp_dbg_f(enc_refs_debug, MPP_ENC_REFS_DBG_FLOW, fmt, ## __VA_ARGS__)
31 #define enc_refs_dbg_frm(fmt, ...) _mpp_dbg(enc_refs_debug, MPP_ENC_REFS_DBG_FRM, fmt, ## __VA_ARGS__)
32 #define enc_refs_dbg_size(fmt, ...) _mpp_dbg(enc_refs_debug, MPP_ENC_REFS_DBG_SIZE, fmt, ## __VA_ARGS__)
33
34 #define ENC_REFS_REF_CFG_CHANGED (0x00000001)
35 #define ENC_REFS_USR_CFG_CHANGED (0x00000002)
36 #define ENC_REFS_IGOP_CHANGED (0x00000004)
37
38 typedef struct RefsCnt_t {
39 RK_S32 delay;
40 RK_S32 delay_cnt;
41 RK_S32 len;
42 RK_S32 cnt;
43 RK_S32 idx;
44
45 RK_S32 lt_idx;
46 RK_S32 tid;
47 MppEncRefMode ref_mode;
48 RK_S32 ref_arg;
49 } RefsCnt;
50
51 typedef struct EncVirtualCpb_t {
52 MppEncCpbInfo info;
53
54 /*
55 * max 32 reference slot for frame searching
56 * (max 16 lt + max 16 st)
57 * st_slot 0 ~ 15
58 * lt_slot 16 ~ 31
59 */
60 EncFrmStatus cpb_refs[MAX_CPB_FRM];
61
62 /* max 32 reference mode */
63 EncFrmStatus mode_refs[MAX_CPB_FRM];
64
65 /*
66 * reference mode storage with args
67 * st + tid - max 16
68 * lt + idx - max 16
69 */
70 EncFrmStatus st_tid_refs[MAX_CPB_TID_FRM];
71 EncFrmStatus lt_idx_refs[MAX_CPB_LT_IDX];
72
73 /* long-term counter */
74 /* lt ref will have multiple counters */
75 RefsCnt lt_cnter[MAX_CPB_LT_IDX];
76
77 /* max two list and each list as two frames */
78 EncFrmStatus list0[2];
79 EncFrmStatus list1[2];
80 /* frame kept in cpb */
81 EncFrmStatus cpb_st[2];
82
83 /* runtime record */
84 RK_S32 frm_idx; /* overall frame index */
85 RK_S32 seq_idx; /* sequence index in one gop */
86 RK_S32 seq_cnt;
87 RK_S32 st_cfg_pos;
88 RK_S32 st_cfg_repeat_pos;
89 } EncVirtualCpb;
90
91 typedef struct MppEncRefsImpl_t {
92 RK_U32 changed;
93 MppEncRefCfgImpl *ref_cfg;
94 MppEncRefFrmUsrCfg usr_cfg;
95 RK_S32 igop;
96 RK_U32 refresh_length;
97
98 RK_S32 hdr_need_update;
99
100 EncVirtualCpb cpb;
101 EncVirtualCpb cpb_stash;
102 } MppEncRefsImpl;
103
104 RK_U32 enc_refs_debug = 0;
105
_dump_frm(EncFrmStatus * frm,const char * func,RK_S32 line)106 void _dump_frm(EncFrmStatus *frm, const char *func, RK_S32 line)
107 {
108 if (!frm->valid)
109 return ;
110
111 if (frm->is_non_ref) {
112 mpp_log("%s:%d valid %d frm %d %s tid %d non-ref -> [%x:%d]\n",
113 func, line, frm->valid, frm->seq_idx,
114 frm->is_intra ? "intra" : "inter",
115 frm->temporal_id, frm->ref_mode, frm->ref_arg);
116 } else if (frm->is_lt_ref) {
117 mpp_log("%s:%d valid %d frm %d %s tid %d lt-ref -> [%x:%d] lt_idx %d\n",
118 func, line, frm->valid, frm->seq_idx,
119 frm->is_intra ? "intra" : "inter",
120 frm->temporal_id, frm->ref_mode, frm->ref_arg,
121 frm->lt_idx);
122 } else {
123 mpp_log("%s:%d valid %d frm %d %s tid %d st-ref -> [%x:%d]\n",
124 func, line, frm->valid, frm->seq_idx,
125 frm->is_intra ? "intra" : "inter",
126 frm->temporal_id, frm->ref_mode, frm->ref_arg);
127 }
128 }
129
130 #define dump_cpb(cpb) _dump_cpb(cpb, __FUNCTION__, __LINE__)
131
_dump_cpb(EncVirtualCpb * cpb,const char * func,RK_S32 line)132 void _dump_cpb(EncVirtualCpb *cpb, const char *func, RK_S32 line)
133 {
134 MppEncCpbInfo *info = &cpb->info;
135 RK_S32 i;
136
137 mpp_log("%s:%d cpb %p status:\n", func, line, cpb);
138 mpp_log("cpb info: dpb_size %d max_lt/st cnt [%d:%d] \n",
139 info->dpb_size, info->max_lt_cnt, info->max_st_cnt);
140 mpp_log("cpb info: max_lt_idx %d max_st_tid %d\n",
141 info->max_lt_idx, info->max_st_tid);
142 mpp_log("cpb info: lt_gop %d st_gop %d\n",
143 info->lt_gop, info->st_gop);
144
145 mpp_log("cpb cpb_refs:\n");
146 for (i = 0; i < MAX_CPB_FRM; i++)
147 dump_frm(&cpb->cpb_refs[i]);
148
149 mpp_log("cpb mode_refs:\n");
150 for (i = 0; i < MAX_CPB_FRM; i++)
151 dump_frm(&cpb->mode_refs[i]);
152
153 mpp_log("cpb st_tid_refs:\n");
154 for (i = 0; i < MAX_CPB_TID_FRM; i++)
155 dump_frm(&cpb->st_tid_refs[i]);
156
157 mpp_log("cpb lt_idx_refs:\n");
158 for (i = 0; i < MAX_CPB_LT_IDX; i++)
159 dump_frm(&cpb->lt_idx_refs[i]);
160
161 mpp_log("cpb runtime: frm_idx %d seq_idx %d seq_cnt %d st_cfg [%d:%d]\n",
162 cpb->frm_idx, cpb->seq_idx, cpb->seq_cnt,
163 cpb->st_cfg_pos, cpb->st_cfg_repeat_pos);
164 }
165
mpp_enc_refs_init(MppEncRefs * refs)166 MPP_RET mpp_enc_refs_init(MppEncRefs *refs)
167 {
168 if (NULL == refs) {
169 mpp_err_f("invalid NULL input refs\n");
170 return MPP_ERR_NULL_PTR;
171 }
172
173 enc_refs_dbg_func("enter %p\n", refs);
174
175 MppEncRefsImpl *p = mpp_calloc(MppEncRefsImpl, 1);
176 *refs = p;
177 if (NULL == p) {
178 mpp_err_f("create refs_impl failed\n");
179 return MPP_ERR_NULL_PTR;
180 }
181
182 mpp_env_get_u32("enc_refs_debug", &enc_refs_debug, 0);
183
184 enc_refs_dbg_func("leave %p\n", p);
185 return MPP_OK;
186 }
187
mpp_enc_refs_deinit(MppEncRefs * refs)188 MPP_RET mpp_enc_refs_deinit(MppEncRefs *refs)
189 {
190 if (NULL == refs) {
191 mpp_err_f("invalid NULL input refs\n");
192 return MPP_ERR_VALUE;
193 }
194
195 enc_refs_dbg_func("enter %p\n", refs);
196
197 MppEncRefsImpl *p = (MppEncRefsImpl *)(*refs);
198 MPP_FREE(p);
199
200 enc_refs_dbg_func("leave %p\n", refs);
201 return MPP_OK;
202 }
203
mpp_enc_refs_set_cfg(MppEncRefs refs,MppEncRefCfg ref_cfg)204 MPP_RET mpp_enc_refs_set_cfg(MppEncRefs refs, MppEncRefCfg ref_cfg)
205 {
206 if (NULL == refs || (ref_cfg && check_is_mpp_enc_ref_cfg(ref_cfg))) {
207 mpp_err_f("invalid input refs %p ref_cfg %p\n", refs, ref_cfg);
208 return MPP_ERR_VALUE;
209 }
210
211 enc_refs_dbg_func("enter %p cfg %p\n", refs, ref_cfg);
212
213 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
214 EncVirtualCpb *cpb = &p->cpb;
215 MppEncRefCfgImpl *cfg = NULL;
216
217 if (NULL == ref_cfg)
218 ref_cfg = mpp_enc_ref_default();
219
220 cfg = (MppEncRefCfgImpl *)ref_cfg;
221
222 p->ref_cfg = cfg;
223 p->changed |= ENC_REFS_REF_CFG_CHANGED;
224 p->hdr_need_update = 0;
225
226 /* clear cpb on setup new cfg */
227 if (!cfg->keep_cpb) {
228 memset(cpb, 0, sizeof(*cpb));
229 p->hdr_need_update = 1;
230 }
231
232 if (cfg->lt_cfg_cnt) {
233 RK_S32 i;
234
235 mpp_assert(cfg->lt_cfg_cnt < MAX_CPB_LT_FRM);
236
237 for (i = 0; i < cfg->lt_cfg_cnt; i++) {
238 RefsCnt *lt_cnt = &cpb->lt_cnter[i];
239 MppEncRefLtFrmCfg *lt_cfg = &cfg->lt_cfg[i];
240
241 lt_cnt->delay = lt_cfg->lt_delay;
242 lt_cnt->delay_cnt = lt_cfg->lt_delay;
243 lt_cnt->len = lt_cfg->lt_gap;
244 lt_cnt->lt_idx = lt_cfg->lt_idx;
245 lt_cnt->tid = lt_cfg->temporal_id;
246 lt_cnt->ref_mode = lt_cfg->ref_mode;
247 lt_cnt->ref_arg = lt_cfg->ref_arg;
248 }
249 }
250
251 MppEncCpbInfo *info = &cpb->info;
252
253 if (info->dpb_size && info->dpb_size < cfg->cpb_info.dpb_size)
254 p->hdr_need_update = 1;
255
256 memcpy(info, &cfg->cpb_info, sizeof(cfg->cpb_info));
257
258 enc_refs_dbg_flow("ref_cfg cpb size: lt %d st %d max lt_idx %d tid %d\n",
259 info->max_lt_cnt, info->max_st_cnt,
260 info->max_lt_idx, info->max_st_tid);
261
262 enc_refs_dbg_func("leave %p cfg %p\n", refs, ref_cfg);
263 return MPP_OK;
264 }
265
cleanup_cpb_refs(EncVirtualCpb * cpb)266 static void cleanup_cpb_refs(EncVirtualCpb *cpb)
267 {
268 RK_U32 i;
269
270 memset(cpb->cpb_refs, 0, sizeof(cpb->cpb_refs));
271 memset(cpb->mode_refs, 0, sizeof(cpb->mode_refs));
272 memset(cpb->st_tid_refs, 0, sizeof(cpb->st_tid_refs));
273 memset(cpb->lt_idx_refs, 0, sizeof(cpb->lt_idx_refs));
274 memset(cpb->list0, 0, sizeof(cpb->list0));
275 memset(cpb->list1, 0, sizeof(cpb->list1));
276 memset(cpb->cpb_st, 0, sizeof(cpb->cpb_st));
277
278 cpb->seq_idx = 0;
279 cpb->seq_cnt++;
280 cpb->st_cfg_pos = 0;
281 cpb->st_cfg_repeat_pos = 0;
282
283 for (i = 0; i < MPP_ARRAY_ELEMS(cpb->lt_cnter); i++) {
284 RefsCnt *lt_cnt = &cpb->lt_cnter[i];
285
286 lt_cnt->delay_cnt = lt_cnt->delay;
287 lt_cnt->cnt = 0;
288 lt_cnt->idx = 0;
289 }
290 }
291
set_st_cfg_to_frm(EncFrmStatus * frm,RK_S32 seq_idx,MppEncRefStFrmCfg * st_cfg)292 static void set_st_cfg_to_frm(EncFrmStatus *frm, RK_S32 seq_idx,
293 MppEncRefStFrmCfg *st_cfg)
294 {
295 memset(frm, 0, sizeof(*frm));
296
297 frm->seq_idx = seq_idx;
298 frm->valid = 1;
299 frm->is_idr = (seq_idx == 0);
300 frm->is_intra = frm->is_idr;
301 frm->is_non_ref = st_cfg->is_non_ref;
302 frm->is_lt_ref = 0;
303 frm->temporal_id = st_cfg->temporal_id;
304 frm->ref_mode = st_cfg->ref_mode;
305 frm->ref_arg = st_cfg->ref_arg;
306
307 if (enc_refs_debug & MPP_ENC_REFS_DBG_FRM)
308 dump_frm(frm);
309 }
310
set_frm_refresh_flag(EncFrmStatus * frm,MppEncRefsImpl * p)311 static MPP_RET set_frm_refresh_flag(EncFrmStatus *frm, MppEncRefsImpl *p)
312 {
313 MPP_RET ret = MPP_OK;
314
315 if (!frm || !p)
316 return ret = MPP_ERR_NULL_PTR;
317
318 if (p->refresh_length) {
319 frm->is_i_refresh = ((frm->seq_idx % p->igop) < p->refresh_length) && p->cpb.seq_cnt > 1;
320 frm->is_i_recovery = !(frm->seq_idx % p->igop) && p->cpb.seq_cnt > 1;
321 } else
322 frm->is_i_refresh = 0;
323
324 return ret;
325 }
326
set_lt_cfg_to_frm(EncFrmStatus * frm,RefsCnt * lt_cfg)327 static void set_lt_cfg_to_frm(EncFrmStatus *frm, RefsCnt *lt_cfg)
328 {
329 frm->is_non_ref = 0;
330 frm->is_lt_ref = 1;
331 frm->temporal_id = lt_cfg->tid;
332 frm->lt_idx = lt_cfg->lt_idx;
333
334 if (lt_cfg->ref_mode != REF_TO_ST_REF_SETUP) {
335 frm->ref_mode = lt_cfg->ref_mode;
336 frm->ref_arg = lt_cfg->ref_arg;
337 }
338
339 if (enc_refs_debug & MPP_ENC_REFS_DBG_FRM)
340 dump_frm(frm);
341 }
342
get_ref_from_cpb(EncVirtualCpb * cpb,EncFrmStatus * frm)343 static EncFrmStatus *get_ref_from_cpb(EncVirtualCpb *cpb, EncFrmStatus *frm)
344 {
345 MppEncRefMode ref_mode = frm->ref_mode;
346 RK_S32 ref_arg = frm->ref_arg;
347
348 if (frm->is_idr)
349 return NULL;
350
351 EncFrmStatus *ref = NULL;
352
353 /* step 3.1 find seq_idx by mode and arg */
354 switch (ref_mode) {
355 case REF_TO_PREV_REF_FRM :
356 case REF_TO_PREV_ST_REF :
357 case REF_TO_PREV_LT_REF :
358 case REF_TO_PREV_INTRA : {
359 ref = &cpb->mode_refs[ref_mode];
360 } break;
361 case REF_TO_TEMPORAL_LAYER : {
362 ref = &cpb->st_tid_refs[ref_arg];
363 } break;
364 case REF_TO_LT_REF_IDX : {
365 ref = &cpb->lt_idx_refs[ref_arg];
366 } break;
367 case REF_TO_ST_PREV_N_REF : {
368 ref = &cpb->cpb_refs[ref_arg];
369 } break;
370 case REF_TO_ST_REF_SETUP :
371 default : {
372 mpp_err_f("frm %d not supported ref mode 0x%x\n", frm->seq_idx, ref_mode);
373 } break;
374 }
375
376 if (ref) {
377 if (ref->valid)
378 enc_refs_dbg_flow("frm %d ref mode %d arg %d -> seq %d %s idx %d\n",
379 frm->seq_idx, ref_mode, ref_arg, ref->seq_idx,
380 ref->is_lt_ref ? "lt" : "st",
381 ref->is_lt_ref ? ref->lt_idx : 0);
382 else
383 mpp_err_f("frm %d found mode %d arg %d -> ref %d but it is invalid\n",
384 frm->seq_idx, ref_mode, ref_arg, ref->seq_idx);
385 } else {
386 ref = NULL;
387 }
388
389 return ref;
390 }
391
check_ref_cpb_pos(EncVirtualCpb * cpb,EncFrmStatus * frm)392 static RK_S32 check_ref_cpb_pos(EncVirtualCpb *cpb, EncFrmStatus *frm)
393 {
394 RK_S32 seq_idx = frm->seq_idx;
395 RK_S32 found = 0;
396 RK_S32 pos = -1;
397
398 if (!frm->valid || frm->is_non_ref) {
399 enc_refs_dbg_flow("frm %d is not valid ref frm\n", seq_idx);
400 return pos;
401 }
402
403 if (frm->is_lt_ref) {
404 /* find same lt_idx */
405 for (pos = 0; pos < MAX_CPB_LT_FRM; pos++) {
406 RK_S32 cpb_idx = pos + MAX_CPB_ST_FRM;
407 EncFrmStatus *cpb_ref = &cpb->cpb_refs[cpb_idx];
408
409 if (cpb_ref->valid && cpb_ref->lt_idx == frm->lt_idx) {
410 pos = cpb_idx;
411 enc_refs_dbg_flow("found ltr ref %d at pos %d\n", seq_idx, pos);
412 found = 1;
413 break;
414 }
415 }
416 } else {
417 /* search seq_idx in cpb to check the st cpb size */
418 for (pos = 0; pos < MAX_CPB_ST_FRM; pos++) {
419 EncFrmStatus *cpb_ref = &cpb->cpb_refs[pos];
420
421 enc_refs_dbg_flow("matching ref %d at pos %d %d\n",
422 seq_idx, pos, cpb_ref->seq_idx);
423
424 if (cpb_ref->valid && cpb_ref->seq_idx == seq_idx) {
425 enc_refs_dbg_flow("found ref %d at pos %d\n", seq_idx, pos);
426 found = 1;
427 break;
428 }
429 }
430 }
431
432 if (!found) {
433 mpp_err_f("frm %d can NOT be found in st refs!!\n", seq_idx);
434 pos = -1;
435 dump_cpb(cpb);
436 }
437
438 return pos;
439 }
440
save_cpb_status(EncVirtualCpb * cpb,EncFrmStatus * refs)441 static void save_cpb_status(EncVirtualCpb *cpb, EncFrmStatus *refs)
442 {
443 EncFrmStatus *ref = &cpb->cpb_refs[MAX_CPB_ST_FRM];
444 MppEncCpbInfo *info = &cpb->info;
445 RK_S32 dpb_size = info->dpb_size;
446 RK_S32 lt_ref_cnt = 0;
447 RK_S32 st_ref_cnt = 0;
448 RK_S32 ref_cnt = 0;
449 RK_S32 i;
450
451 /* save lt ref */
452 for (i = 0; i < info->max_lt_cnt; i++, ref++) {
453 if (!ref->valid || ref->is_non_ref || !ref->is_lt_ref)
454 continue;
455
456 mpp_assert(!ref->is_non_ref);
457 mpp_assert(ref->is_lt_ref);
458 mpp_assert(ref->lt_idx >= 0);
459
460 enc_refs_dbg_flow("save lt ref %d to slot %d\n", ref->seq_idx, ref_cnt);
461 refs[ref_cnt++].val = ref->val;
462 lt_ref_cnt++;
463 }
464
465 ref = &cpb->cpb_refs[0];
466 /* save st ref */
467 if (ref_cnt < dpb_size) {
468 RK_S32 max_st_cnt = info->max_st_cnt;
469
470 if (max_st_cnt < dpb_size - ref_cnt)
471 max_st_cnt = dpb_size - ref_cnt;
472
473 for (i = 0; i < max_st_cnt; i++, ref++) {
474 if (!ref->valid || ref->is_non_ref || ref->is_lt_ref)
475 continue;
476
477 mpp_assert(!ref->is_non_ref);
478 mpp_assert(!ref->is_lt_ref);
479 mpp_assert(ref->temporal_id >= 0);
480
481 enc_refs_dbg_flow("save st ref %d to slot %d\n", ref->seq_idx, ref_cnt);
482 refs[ref_cnt++].val = ref->val;
483 st_ref_cnt++;
484 }
485 }
486
487 enc_refs_dbg_flow("save ref total %d lt %d st %d\n", ref_cnt, lt_ref_cnt, st_ref_cnt);
488 if (enc_refs_debug & MPP_ENC_REFS_DBG_FLOW)
489 for (i = 0; i < ref_cnt; i++)
490 dump_frm(&refs[i]);
491 }
492
store_ref_to_cpb(EncVirtualCpb * cpb,EncFrmStatus * frm)493 static void store_ref_to_cpb(EncVirtualCpb *cpb, EncFrmStatus *frm)
494 {
495 RK_S32 seq_idx = frm->seq_idx;
496 RK_S32 lt_idx = frm->lt_idx;
497 RK_S32 tid = frm->temporal_id;
498 RK_S32 i;
499
500 mpp_assert(frm->valid);
501 mpp_assert(lt_idx < MAX_CPB_LT_IDX);
502 mpp_assert(tid < MAX_CPB_LT_FRM);
503
504 /* non-ref do not save to cpb */
505 if (frm->is_non_ref)
506 return ;
507
508 if (frm->is_intra)
509 cpb->mode_refs[REF_TO_PREV_INTRA].val = frm->val;
510
511 if (frm->is_lt_ref) {
512 cpb->lt_idx_refs[lt_idx].val = frm->val;
513 cpb->st_tid_refs[tid].val = frm->val;
514 cpb->mode_refs[REF_TO_PREV_REF_FRM].val = frm->val;
515 cpb->mode_refs[REF_TO_PREV_LT_REF].val = frm->val;
516
517 RK_S32 found = 0;
518 EncFrmStatus *cpb_ref = NULL;
519
520 /* find same lt_idx and replace */
521 for (i = 0; i < MAX_CPB_LT_FRM; i++) {
522 RK_S32 cpb_idx = i + MAX_CPB_ST_FRM;
523 cpb_ref = &cpb->cpb_refs[cpb_idx];
524
525 if (!cpb_ref->valid) {
526 found = 1;
527 break;
528 } else {
529 if (cpb_ref->lt_idx == lt_idx) {
530 found = 2;
531 break;
532 }
533 }
534 }
535
536 if (found) {
537 cpb_ref->val = frm->val;
538 enc_refs_dbg_flow("frm %d with lt idx %d %s to pos %d\n",
539 seq_idx, lt_idx, (found == 1) ? "add" : "replace", i);
540 } else {
541 mpp_err_f("frm %d with lt idx %d found no place to add or relace\n",
542 seq_idx, lt_idx);
543 }
544 } else {
545 /* do normal st sliding window */
546 cpb->st_tid_refs[tid].val = frm->val;
547 cpb->mode_refs[REF_TO_PREV_REF_FRM].val = frm->val;
548 cpb->mode_refs[REF_TO_PREV_ST_REF].val = frm->val;
549
550 for (i = MAX_CPB_ST_FRM - 1; i > 0; i--)
551 cpb->cpb_refs[i].val = cpb->cpb_refs[i - 1].val;
552
553 cpb->cpb_refs[0].val = frm->val;
554
555 // TODO: Add prev intra valid check?
556 }
557
558 enc_refs_dbg_flow("dumping cpb refs status start\n");
559 if (enc_refs_debug & MPP_ENC_REFS_DBG_FLOW)
560 for (i = 0; i < MAX_CPB_FRM; i++)
561 if (cpb->cpb_refs[i].valid)
562 dump_frm(&cpb->cpb_refs[i]);
563
564 enc_refs_dbg_flow("dumping cpb refs status done\n");
565 }
566
mpp_enc_refs_dryrun(MppEncRefs refs)567 MPP_RET mpp_enc_refs_dryrun(MppEncRefs refs)
568 {
569 if (NULL == refs) {
570 mpp_err_f("invalid NULL input refs\n");
571 return MPP_ERR_VALUE;
572 }
573
574 enc_refs_dbg_func("enter %p\n", refs);
575
576 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
577 MppEncRefCfgImpl *cfg = p->ref_cfg;
578 MppEncRefStFrmCfg *st_cfg = cfg->st_cfg;
579 EncVirtualCpb *cpb = &p->cpb;
580 MppEncCpbInfo *info = &cpb->info;
581 RK_S32 lt_cfg_cnt = cfg->lt_cfg_cnt;
582 RK_S32 st_cfg_cnt = cfg->st_cfg_cnt;
583 RK_S32 cpb_st_used_size = 0;
584 RK_S32 seq_idx = 0;
585 RK_S32 st_idx;
586 RK_S32 walk_len = MPP_MAX(lt_cfg_cnt, st_cfg_cnt);
587
588 if (cfg->ready)
589 goto DONE;
590
591 cleanup_cpb_refs(cpb);
592
593 cfg->max_tlayers = cpb->info.max_st_tid + 1;
594 enc_refs_dbg_flow("dryrun start: lt_cfg %d st_cfg %d\n",
595 lt_cfg_cnt, st_cfg_cnt);
596
597 for (st_idx = 0; st_idx < walk_len; st_idx++) {
598 st_cfg = &cfg->st_cfg[st_idx % st_cfg_cnt];
599 EncFrmStatus frm;
600 RK_S32 repeat = (st_cfg->repeat) ? st_cfg->repeat : 1;
601
602 while (repeat-- > 0) {
603 /* step 1. updated by st_cfg */
604 set_st_cfg_to_frm(&frm, seq_idx++, st_cfg);
605 set_frm_refresh_flag(&frm, p);
606
607 /* step 2. updated by lt_cfg */
608 RefsCnt *lt_cfg = &cpb->lt_cnter[0];
609 RK_S32 set_to_lt = 0;
610 RK_S32 i;
611
612 for (i = 0; i < lt_cfg_cnt; i++, lt_cfg++) {
613 if (lt_cfg->delay_cnt) {
614 lt_cfg->delay_cnt--;
615 continue;
616 }
617
618 if (!set_to_lt) {
619 if (!lt_cfg->cnt) {
620 set_lt_cfg_to_frm(&frm, lt_cfg);
621 set_to_lt = 1;
622 }
623 }
624
625 lt_cfg->cnt++;
626 if (lt_cfg->cnt >= lt_cfg->len) {
627 if (lt_cfg->len) {
628 /* when there is loop len loop lt_cfg */
629 lt_cfg->cnt = 0;
630 lt_cfg->idx++;
631 } else {
632 /* else just set lt_cfg once */
633 lt_cfg->cnt = 1;
634 lt_cfg->idx = 1;
635 }
636 }
637 }
638
639 /* step 3. try find ref by the ref_mode and update used cpb size */
640 EncFrmStatus *ref = get_ref_from_cpb(cpb, &frm);
641
642 if (ref) {
643 RK_S32 cpb_pos = check_ref_cpb_pos(cpb, ref);
644
645 if (cpb_pos < MAX_CPB_ST_FRM) {
646 if (cpb_st_used_size < cpb_pos + 1) {
647 cpb_st_used_size = cpb_pos + 1;
648 enc_refs_dbg_flow("cpb_st_used_size update to %d\n", cpb_st_used_size);
649 }
650 }
651 }
652
653 /* step 4. store frame according to status */
654 store_ref_to_cpb(cpb, &frm);
655 }
656 }
657
658 cleanup_cpb_refs(cpb);
659 info->max_st_cnt = cpb_st_used_size ? cpb_st_used_size : 1;
660
661 DONE:
662 info->dpb_size = info->max_lt_cnt + info->max_st_cnt;
663
664 enc_refs_dbg_size("dryrun success: cpb size %d\n", info->dpb_size);
665
666 enc_refs_dbg_func("leave %p\n", refs);
667 return MPP_OK;
668 }
669
mpp_enc_refs_set_usr_cfg(MppEncRefs refs,MppEncRefFrmUsrCfg * cfg)670 MPP_RET mpp_enc_refs_set_usr_cfg(MppEncRefs refs, MppEncRefFrmUsrCfg *cfg)
671 {
672 if (NULL == refs) {
673 mpp_err_f("invalid NULL input refs\n");
674 return MPP_ERR_VALUE;
675 }
676
677 enc_refs_dbg_func("enter %p\n", refs);
678
679 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
680 memcpy(&p->usr_cfg, cfg, sizeof(p->usr_cfg));
681 if (cfg->force_flag)
682 p->changed |= ENC_REFS_USR_CFG_CHANGED;
683
684 enc_refs_dbg_func("leave %p\n", refs);
685 return MPP_OK;
686 }
687
mpp_enc_refs_set_rc_igop(MppEncRefs refs,RK_S32 igop)688 MPP_RET mpp_enc_refs_set_rc_igop(MppEncRefs refs, RK_S32 igop)
689 {
690 if (NULL == refs) {
691 mpp_err_f("invalid NULL input refs\n");
692 return MPP_ERR_VALUE;
693 }
694
695 enc_refs_dbg_func("enter %p\n", refs);
696
697 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
698
699 if (p->igop != igop) {
700 p->igop = igop;
701 p->changed |= ENC_REFS_IGOP_CHANGED;
702 }
703
704 enc_refs_dbg_func("leave %p\n", refs);
705 return MPP_OK;
706 }
707
mpp_enc_refs_set_refresh_length(MppEncRefs refs,RK_S32 len)708 MPP_RET mpp_enc_refs_set_refresh_length(MppEncRefs refs, RK_S32 len)
709 {
710 MPP_RET ret = MPP_OK;
711 if (NULL == refs) {
712 mpp_err_f("invalid NULL input refs\n");
713 return MPP_ERR_VALUE;
714 }
715
716 enc_refs_dbg_func("enter %p\n", refs);
717
718 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
719
720 if (len < p->igop) {
721 p->refresh_length = len;
722 } else {
723 p->refresh_length = p->igop;
724 ret = MPP_ERR_VALUE;
725 goto RET;
726 }
727 enc_refs_dbg_func("leave %p\n", refs);
728 RET:
729 return ret;
730 }
731
mpp_enc_refs_update_hdr(MppEncRefs refs)732 RK_S32 mpp_enc_refs_update_hdr(MppEncRefs refs)
733 {
734 if (NULL == refs) {
735 mpp_err_f("invalid NULL input refs\n");
736 return 0;
737 }
738
739 enc_refs_dbg_func("enter %p\n", refs);
740
741 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
742 RK_S32 hdr_need_update = p->hdr_need_update;
743
744 enc_refs_dbg_func("leave %p\n", refs);
745 return hdr_need_update;
746 }
747
mpp_enc_refs_get_cpb_info(MppEncRefs refs,MppEncCpbInfo * info)748 MPP_RET mpp_enc_refs_get_cpb_info(MppEncRefs refs, MppEncCpbInfo *info)
749 {
750 if (NULL == refs || NULL == info) {
751 mpp_err_f("invalid input refs %p info %p\n", refs, info);
752 return MPP_ERR_VALUE;
753 }
754
755 enc_refs_dbg_func("enter %p\n", refs);
756
757 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
758 memcpy(info, &p->cpb.info, sizeof(*info));
759
760 enc_refs_dbg_func("leave %p\n", refs);
761 return MPP_OK;
762 }
763
get_cpb_st_cfg_pos(EncVirtualCpb * cpb,MppEncRefCfgImpl * cfg)764 static RK_S32 get_cpb_st_cfg_pos(EncVirtualCpb *cpb, MppEncRefCfgImpl *cfg)
765 {
766 RK_S32 st_cfg_pos = cpb->st_cfg_pos;
767 RK_S32 st_cfg_cnt = cfg->st_cfg_cnt;
768
769 /* NOTE: second loop will start from 1 */
770 if (st_cfg_pos >= st_cfg_cnt)
771 st_cfg_pos = (st_cfg_cnt > 1) ? (1) : (0);
772
773 return st_cfg_pos;
774 }
775
mpp_enc_refs_get_cpb(MppEncRefs refs,EncCpbStatus * status)776 MPP_RET mpp_enc_refs_get_cpb(MppEncRefs refs, EncCpbStatus *status)
777 {
778 if (NULL == refs) {
779 mpp_err_f("invalid NULL input refs\n");
780 return MPP_ERR_VALUE;
781 }
782
783 enc_refs_dbg_func("enter %p\n", refs);
784
785 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
786 MppEncRefCfgImpl *cfg = p->ref_cfg;
787 EncVirtualCpb *cpb = &p->cpb;
788 MppEncRefStFrmCfg *st_cfg = NULL;
789 MppEncRefFrmUsrCfg *usr_cfg = &p->usr_cfg;
790 EncFrmStatus *frm = &status->curr;
791 EncFrmStatus *ref = &status->refr;
792 RefsCnt *lt_cfg = cpb->lt_cnter;
793 RK_S32 set_to_lt = 0;
794 RK_S32 cleanup_cpb = 0;
795 RK_S32 prev_frm_is_pass1 = frm->save_pass1;
796 RK_S32 i;
797
798 /* step 1. check igop from cfg_set and force idr for usr_cfg */
799 if (p->changed & ENC_REFS_IGOP_CHANGED)
800 cleanup_cpb = 1;
801
802 if (p->igop && (cpb->seq_idx >= p->igop)) {
803 if (p->refresh_length) {
804 p->cpb.seq_cnt = cpb->seq_idx / p->igop + 1;
805 } else
806 cleanup_cpb = 1;
807 }
808
809 if (usr_cfg->force_flag & ENC_FORCE_IDR) {
810 usr_cfg->force_flag &= (~ENC_FORCE_IDR);
811 cleanup_cpb = 1;
812 p->cpb.seq_cnt = 0;
813 }
814
815 if (cleanup_cpb) {
816 /* update seq_idx for igop loop and force idr */
817 cleanup_cpb_refs(cpb);
818 } else if (p->changed & ENC_REFS_REF_CFG_CHANGED) {
819 cpb->st_cfg_pos = 0;
820 cpb->st_cfg_repeat_pos = 0;
821 }
822
823 p->changed = 0;
824
825 cpb->frm_idx++;
826 cpb->st_cfg_pos = get_cpb_st_cfg_pos(cpb, cfg);
827 st_cfg = &cfg->st_cfg[cpb->st_cfg_pos];
828 /* step 2. updated by st_cfg */
829 set_st_cfg_to_frm(frm, cpb->seq_idx++, st_cfg);
830 set_frm_refresh_flag(frm, p);
831
832 lt_cfg = p->cpb.lt_cnter;
833
834 /* step 3. updated by lt_cfg */
835 for (i = 0; i < cfg->lt_cfg_cnt; i++, lt_cfg++) {
836 if (lt_cfg->delay_cnt) {
837 lt_cfg->delay_cnt--;
838 continue;
839 }
840
841 if (!set_to_lt) {
842 if (!lt_cfg->cnt) {
843 set_lt_cfg_to_frm(frm, lt_cfg);
844 set_to_lt = 1;
845 }
846 }
847
848 lt_cfg->cnt++;
849 if (lt_cfg->cnt >= lt_cfg->len) {
850 if (lt_cfg->len) {
851 /* when there is loop len loop lt_cfg */
852 lt_cfg->cnt = 0;
853 lt_cfg->idx++;
854 } else {
855 /* else just set lt_cfg once */
856 lt_cfg->cnt = 1;
857 lt_cfg->idx = 1;
858 }
859 }
860 }
861
862 /* step 4. process force flags and force ref_mode */
863 if (usr_cfg->force_flag & ENC_FORCE_LT_REF_IDX) {
864 frm->is_non_ref = 0;
865 frm->is_lt_ref = 1;
866 frm->lt_idx = usr_cfg->force_lt_idx;
867 if (frm->is_idr && frm->lt_idx) {
868 frm->lt_idx = 0;
869 mpp_err_f("can not set IDR to ltr with non-zero index\n");
870 }
871 /* lt_ref will be forced to tid 0 */
872 frm->temporal_id = 0;
873
874 /* reset st_cfg to next loop */
875 cpb->st_cfg_repeat_pos = 0;
876 cpb->st_cfg_pos = 0;
877 usr_cfg->force_flag &= ~ENC_FORCE_LT_REF_IDX;
878 }
879
880 if (usr_cfg->force_flag & ENC_FORCE_TEMPORAL_ID) {
881 if (usr_cfg->force_temporal_id >= cfg->max_tlayers ||
882 frm->is_idr || frm->is_lt_ref)
883 mpp_err_f("Invalid temporal_id %d, frm is %s\n", usr_cfg->force_temporal_id,
884 frm->is_idr ? "IDR" : (frm->is_lt_ref ? "LTR" : "st"));
885 else
886 frm->temporal_id = usr_cfg->force_temporal_id;
887
888 usr_cfg->force_flag &= ~ENC_FORCE_TEMPORAL_ID;
889 }
890
891 if (usr_cfg->force_flag & ENC_FORCE_REF_MODE) {
892 frm->ref_mode = usr_cfg->force_ref_mode;
893 frm->ref_arg = usr_cfg->force_ref_arg;
894
895 usr_cfg->force_flag &= ~ENC_FORCE_REF_MODE;
896 }
897
898 if (usr_cfg->force_flag & ENC_FORCE_PSKIP_NON_REF) {
899 frm->is_non_ref = 1;
900
901 usr_cfg->force_flag &= ~ENC_FORCE_PSKIP_NON_REF;
902 }
903
904 if (usr_cfg->force_flag & ENC_FORCE_PSKIP_IS_REF) {
905 frm->force_pskip_is_ref = 1;
906
907 usr_cfg->force_flag &= ~ENC_FORCE_PSKIP_IS_REF;
908 }
909
910 frm->non_recn = frm->is_non_ref || (p->igop == 1);
911
912 /* update st_cfg for st_cfg loop */
913 cpb->st_cfg_repeat_pos++;
914 if (cpb->st_cfg_repeat_pos > st_cfg->repeat) {
915 cpb->st_cfg_repeat_pos = 0;
916 cpb->st_cfg_pos++;
917 }
918
919 /* step 4. try find ref by the ref_mode */
920 EncFrmStatus *ref_found = get_ref_from_cpb(&p->cpb, frm);
921 if (ref_found) {
922 RK_S32 cpb_idx = check_ref_cpb_pos(&p->cpb, ref_found);
923
924 mpp_assert(cpb_idx >= 0);
925 cpb->list0[0].val = ref->val;
926 ref->val = ref_found->val;
927 } else
928 ref->val = 0;
929
930 /* step 5. check use previous pass one frame as input */
931 if (prev_frm_is_pass1)
932 frm->use_pass1 = 1;
933
934 if (enc_refs_debug & MPP_ENC_REFS_DBG_FRM) {
935 mpp_log_f("frm status:\n");
936 dump_frm(frm);
937 mpp_log_f("ref status:\n");
938 dump_frm(ref);
939 }
940
941 /* step 5. generate cpb init */
942 memset(status->init, 0, sizeof(status->init));
943 save_cpb_status(&p->cpb, status->init);
944 // TODO: cpb_init must be the same to cpb_final
945
946 /* step 6. store frame according to status */
947 store_ref_to_cpb(&p->cpb, frm);
948
949 /* step 7. generate cpb final */
950 memset(status->final, 0, sizeof(status->final));
951 save_cpb_status(&p->cpb, status->final);
952
953 enc_refs_dbg_func("leave %p\n", refs);
954 return MPP_OK;
955 }
956
mpp_enc_refs_next_frm_is_intra(MppEncRefs refs)957 RK_S32 mpp_enc_refs_next_frm_is_intra(MppEncRefs refs)
958 {
959 if (NULL == refs) {
960 mpp_err_f("invalid NULL input refs\n");
961 return MPP_ERR_VALUE;
962 }
963
964 enc_refs_dbg_func("enter %p\n", refs);
965
966 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
967 EncVirtualCpb *cpb = &p->cpb;
968 MppEncRefFrmUsrCfg *usr_cfg = &p->usr_cfg;
969 RK_S32 is_intra = 0;
970
971 if (p->changed & ENC_REFS_IGOP_CHANGED)
972 is_intra = 1;
973
974 if (p->igop && cpb->seq_idx >= p->igop)
975 is_intra = 1;
976
977 if (usr_cfg->force_flag & ENC_FORCE_IDR)
978 is_intra = 1;
979
980 if (!cpb->frm_idx)
981 is_intra = 0;
982
983 enc_refs_dbg_func("leave %p\n", refs);
984
985 return is_intra;
986 }
987
mpp_enc_refs_get_cpb_pass1(MppEncRefs refs,EncCpbStatus * status)988 MPP_RET mpp_enc_refs_get_cpb_pass1(MppEncRefs refs, EncCpbStatus *status)
989 {
990 if (NULL == refs) {
991 mpp_err_f("invalid NULL input refs\n");
992 return MPP_ERR_VALUE;
993 }
994
995 enc_refs_dbg_func("enter %p\n", refs);
996
997 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
998 EncVirtualCpb *cpb = &p->cpb;
999 EncFrmStatus *frm = &status->curr;
1000 EncFrmStatus *ref = &status->refr;
1001
1002 frm->valid = 1;
1003 frm->save_pass1 = 1;
1004 frm->is_non_ref = 1;
1005 frm->is_lt_ref = 0;
1006 frm->temporal_id = 0;
1007 frm->ref_mode = REF_TO_PREV_REF_FRM;
1008 frm->ref_arg = 0;
1009 frm->non_recn = 0;
1010
1011 /* step 4. try find ref by the ref_mode */
1012 EncFrmStatus *ref_found = get_ref_from_cpb(cpb, frm);
1013 if (ref_found) {
1014 RK_S32 cpb_idx = check_ref_cpb_pos(cpb, ref_found);
1015
1016 mpp_assert(cpb_idx >= 0);
1017 cpb->list0[0].val = ref->val;
1018 ref->val = ref_found->val;
1019 } else
1020 ref->val = 0;
1021
1022 if (enc_refs_debug & MPP_ENC_REFS_DBG_FRM) {
1023 mpp_log_f("frm status:\n");
1024 dump_frm(frm);
1025 mpp_log_f("ref status:\n");
1026 dump_frm(ref);
1027 }
1028
1029 /* step 5. generate cpb init */
1030 memset(status->init, 0, sizeof(status->init));
1031 save_cpb_status(cpb, status->init);
1032 // TODO: cpb_init must be the same to cpb_final
1033
1034 /* step 6. store frame according to status */
1035 store_ref_to_cpb(cpb, frm);
1036
1037 /* step 7. generate cpb final */
1038 memset(status->final, 0, sizeof(status->final));
1039 save_cpb_status(cpb, status->final);
1040
1041 enc_refs_dbg_func("leave %p\n", refs);
1042 return MPP_OK;
1043 }
mpp_enc_refs_stash(MppEncRefs refs)1044 MPP_RET mpp_enc_refs_stash(MppEncRefs refs)
1045 {
1046 if (NULL == refs) {
1047 mpp_err_f("invalid NULL input refs\n");
1048 return MPP_ERR_VALUE;
1049 }
1050
1051 enc_refs_dbg_func("enter %p\n", refs);
1052
1053 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
1054 memcpy(&p->cpb_stash, &p->cpb, sizeof(p->cpb_stash));
1055
1056 enc_refs_dbg_func("leave %p\n", refs);
1057 return MPP_OK;
1058 }
1059
mpp_enc_refs_rollback(MppEncRefs refs)1060 MPP_RET mpp_enc_refs_rollback(MppEncRefs refs)
1061 {
1062 if (NULL == refs) {
1063 mpp_err_f("invalid NULL input refs\n");
1064 return MPP_ERR_VALUE;
1065 }
1066
1067 enc_refs_dbg_func("enter %p\n", refs);
1068
1069 MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
1070 memcpy(&p->cpb, &p->cpb_stash, sizeof(p->cpb));
1071
1072 enc_refs_dbg_func("leave %p\n", refs);
1073 return MPP_OK;
1074 }
1075