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