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