xref: /rockchip-linux_mpp/mpp/base/mpp_enc_refs.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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