/* SPDX-License-Identifier: Apache-2.0 OR MIT */ /* * Copyright (c) 2015 Rockchip Electronics Co., Ltd. */ #define MODULE_TAG "mpp_enc_ref" #include #include "mpp_log.h" #include "mpp_trie.h" #include "mpp_common.h" #include "mpp_cfg_io.h" #include "mpp_enc_ref.h" #include "mpp_enc_refs.h" #include "rk_venc_kcfg.h" #define ENC_REF_POS_SEEK(ref, pos, arr, idx, name) do { \ rk_s32 _r = kmpp_obj_pos_seek((ref), (pos), (name), (idx)); \ if (_r) { \ mpp_loge_f("kobj %s [%d] seek failed ret %d\n", (arr), (idx), _r); \ return MPP_NOK; \ } \ } while (0) #define ENC_REF_ST_POS_GET_FIELD(ref, pos, idx, field, val) do { \ rk_s32 _r = kmpp_obj_pos_get_s32((ref), (pos), #field, (val)); \ if (_r) { \ mpp_loge_f("kobj st_cfg [%d] get %s failed ret %d\n", \ (idx), #field, _r); \ return MPP_NOK; \ } \ } while (0) #define ENC_REF_ST_POS_SET_FIELD(ref, pos, idx, field, val) do { \ rk_s32 _r = kmpp_obj_pos_set_s32((ref), (pos), #field, (val)); \ if (_r) { \ mpp_loge_f("kobj st_cfg [%d] set %s failed ret %d\n", \ (idx), #field, _r); \ return MPP_NOK; \ } \ } while (0) #define ENC_REF_LT_POS_GET_FIELD(ref, pos, idx, field, val) do { \ rk_s32 _r = kmpp_obj_pos_get_s32((ref), (pos), #field, (val)); \ if (_r) { \ mpp_loge_f("kobj lt_cfg [%d] get %s failed ret %d\n", \ (idx), #field, _r); \ return MPP_NOK; \ } \ } while (0) #define ENC_REF_LT_POS_SET_FIELD(ref, pos, idx, field, val) do { \ rk_s32 _r = kmpp_obj_pos_set_s32((ref), (pos), #field, (val)); \ if (_r) { \ mpp_loge_f("kobj lt_cfg [%d] set %s failed ret %d\n", \ (idx), #field, _r); \ return MPP_NOK; \ } \ } while (0) /* * kmpp_obj definition for MppEncRefCfgImpl */ #define MPP_ENC_REF_CFG_ENTRY_TABLE(prefix, ENTRY, STRCT, EHOOK, SHOOK, ALIAS) \ CFG_DEF_START() \ ENTRY(prefix, s32, rk_s32, keep_cpb, FLAG_INCR, keep_cpb) \ ENTRY(prefix, s32, rk_s32, lt_cfg_cap, FLAG_INCR, new_lt_cfg_cap) \ ENTRY(prefix, s32, rk_s32, st_cfg_cap, FLAG_INCR, new_st_cfg_cap) \ ENTRY(prefix, u32, rk_u32, lt_cfg_off, FLAG_NONE, lt_cfg_off) \ ENTRY(prefix, u32, rk_u32, st_cfg_off, FLAG_NONE, st_cfg_off) \ ENTRY(prefix, s32, rk_s32, lt_cfg_cnt, FLAG_INCR, lt_cfg_cnt) \ ENTRY(prefix, s32, rk_s32, st_cfg_cnt, FLAG_INCR, st_cfg_cnt) \ ENTRY(prefix, s32, rk_s32, max_tlayers, FLAG_INCR, max_tlayers) \ ENTRY(prefix, s32, rk_s32, ready, FLAG_INCR, ready) \ ARRAY_START_FLEX_CNT_OFF(st_cfg, MppEncRefStFrmCfg, FLAG_INCR, st_cfg_cap, st_cfg_off) \ ARRAY_ENTRY(s32, is_non_ref, FLAG_PREV, is_non_ref) \ ARRAY_ENTRY(s32, temporal_id, FLAG_PREV, temporal_id) \ ARRAY_ENTRY(s32, ref_mode, FLAG_PREV, ref_mode) \ ARRAY_ENTRY(s32, ref_arg, FLAG_PREV, ref_arg) \ ARRAY_ENTRY(s32, repeat, FLAG_PREV, repeat) \ ARRAY_END(st_cfg) \ ARRAY_START_FLEX_CNT_OFF(lt_cfg, MppEncRefLtFrmCfg, FLAG_INCR, lt_cfg_cap, lt_cfg_off) \ ARRAY_ENTRY(s32, lt_idx, FLAG_PREV, lt_idx) \ ARRAY_ENTRY(s32, temporal_id, FLAG_PREV, temporal_id) \ ARRAY_ENTRY(s32, ref_mode, FLAG_PREV, ref_mode) \ ARRAY_ENTRY(s32, ref_arg, FLAG_PREV, ref_arg) \ ARRAY_ENTRY(s32, lt_gap, FLAG_PREV, lt_gap) \ ARRAY_ENTRY(s32, lt_delay, FLAG_PREV, lt_delay) \ ARRAY_END(lt_cfg) \ CFG_DEF_END() static rk_s32 mpp_enc_ref_cfg_impl_dump(void *entry) { MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)entry; rk_s32 i; if (!cfg) { mpp_loge_f("invalid param entry NULL\n"); return rk_nok; } mpp_logi("keep_cpb %d\n", cfg->keep_cpb); mpp_logi("st_cfg_cnt %d / %d off %u\n", cfg->st_cfg_cnt, cfg->st_cfg_cap, cfg->st_cfg_off); mpp_logi("lt_cfg_cnt %d / %d off %u\n", cfg->lt_cfg_cnt, cfg->lt_cfg_cap, cfg->lt_cfg_off); mpp_logi("max_tlayers %d\n", cfg->max_tlayers); mpp_logi("ready %d\n", cfg->ready); for (i = 0; i < cfg->st_cfg_cnt; i++) { MppEncRefStFrmCfg *st = &MPP_REF_ST_ARR(cfg)[i]; mpp_logi(" st[%d] non_ref %d tid %d mode %x arg %d repeat %d\n", i, st->is_non_ref, st->temporal_id, st->ref_mode, st->ref_arg, st->repeat); } for (i = 0; i < cfg->lt_cfg_cnt; i++) { MppEncRefLtFrmCfg *lt = &MPP_REF_LT_ARR(cfg)[i]; mpp_logi(" lt[%d] idx %d tid %d mode %x arg %d gap %d delay %d\n", i, lt->lt_idx, lt->temporal_id, lt->ref_mode, lt->ref_arg, lt->lt_gap, lt->lt_delay); } return rk_ok; } static rk_s32 mpp_enc_ref_cfg_impl_resize(void *entry, KmppObj obj, const char *caller) { MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)entry; KmppObjDef def = kmpp_obj_to_objdef(obj); rk_u32 old_lt_off = cfg->lt_cfg_off; rk_s32 data_off; (void)caller; data_off = kmpp_objdef_get_entry_size(def) + kmpp_obj_to_flags_size(obj); cfg->st_cfg_off = data_off; cfg->lt_cfg_off = data_off + cfg->new_st_cfg_cap * sizeof(MppEncRefStFrmCfg); /* relocate lt cfg data when offset shifts */ { rk_s32 old_lt_cfg_cap = cfg->lt_cfg_cap; rk_s32 move_cnt = MPP_MIN3(cfg->lt_cfg_cnt, cfg->new_lt_cfg_cap, old_lt_cfg_cap); if (old_lt_off && cfg->lt_cfg_off != old_lt_off && move_cnt > 0) memmove((char *)cfg + cfg->lt_cfg_off, (char *)cfg + old_lt_off, move_cnt * sizeof(MppEncRefLtFrmCfg)); } /* commit new caps to actual fields */ cfg->lt_cfg_cap = cfg->new_lt_cfg_cap; cfg->st_cfg_cap = cfg->new_st_cfg_cap; return rk_ok; } #define KMPP_OBJ_NAME mpp_enc_ref_cfg #define KMPP_OBJ_INTF_TYPE MppEncRefCfg #define KMPP_OBJ_IMPL_TYPE MppEncRefCfgImpl #define KMPP_OBJ_SGLN_ID MPP_SGLN_ENC_REF_CFG #define KMPP_OBJ_ENTRY_TABLE MPP_ENC_REF_CFG_ENTRY_TABLE #define KMPP_OBJ_FUNC_DUMP mpp_enc_ref_cfg_impl_dump #define KMPP_OBJ_FUNC_RESIZE mpp_enc_ref_cfg_impl_resize #define KMPP_OBJ_ACCESS_DISABLE #define KMPP_OBJ_HIERARCHY_ENABLE #define KMPP_OBJ_FLEX_ENTRY_ENABLE #include "kmpp_obj_helper.h" /* * ref_cfg_resize - set pending caps and resize VLA * * Stores requested caps in new_lt/st_cfg_cap, then calls kmpp_obj_resize. * The resize callback commits new_* to actual cap fields. * On failure, clears new_* (old state unchanged since callback not called). */ static rk_s32 ref_cfg_resize(MppEncRefCfg obj, rk_s32 new_lt_cap, rk_s32 new_st_cap, const char *caller) { rk_s32 old_lt_cap; rk_s32 old_st_cap; rk_s32 vla_size; rk_s32 ret; kmpp_obj_get_s32(obj, "lt_cfg_cap", &old_lt_cap); kmpp_obj_get_s32(obj, "st_cfg_cap", &old_st_cap); kmpp_obj_set_s32(obj, "lt_cfg_cap", new_lt_cap); kmpp_obj_set_s32(obj, "st_cfg_cap", new_st_cap); vla_size = new_st_cap * sizeof(MppEncRefStFrmCfg) + new_lt_cap * sizeof(MppEncRefLtFrmCfg); ret = kmpp_obj_resize(obj, vla_size, caller); if (ret) { mpp_loge("%s: resize to %d failed ret %d, revert to cap lt %d st %d\n", caller, vla_size, ret, old_lt_cap, old_st_cap); kmpp_obj_set_s32(obj, "lt_cfg_cap", old_lt_cap); kmpp_obj_set_s32(obj, "st_cfg_cap", old_st_cap); } return ret; } MPP_RET mpp_enc_ref_cfg_setup(MppEncRefCfg obj, RK_S32 lt_cnt, RK_S32 st_cnt) { rk_s32 ret; if (!obj || lt_cnt < 0 || st_cnt < 0) { mpp_loge_f("invalid param obj %p lt_cnt %d st_cnt %d\n", obj, lt_cnt, st_cnt); return MPP_NOK; } if (!kmpp_obj_to_entry(obj)) return MPP_ERR_NULL_PTR; ret = ref_cfg_resize(obj, lt_cnt, st_cnt, __FUNCTION__); if (ret) return ret; kmpp_obj_set_s32(obj, "lt_cfg_cnt", 0); kmpp_obj_set_s32(obj, "st_cfg_cnt", 0); return MPP_OK; } /* * mpp_enc_ref_cfg API implementation */ MPP_RET mpp_enc_ref_cfg_init(MppEncRefCfg *ref) { MPP_RET ret; if (NULL == ref) { mpp_loge_f("invalid NULL input ref_cfg\n"); return MPP_ERR_NULL_PTR; } ret = mpp_enc_ref_cfg_get(ref); if (ret) return ret; return mpp_enc_ref_cfg_reset(*ref); } MPP_RET mpp_enc_ref_cfg_create(MppEncRefCfg *ref, RK_U32 mode) { if (NULL == ref) return MPP_ERR_NULL_PTR; if (mode >= 2) return mpp_venc_kcfg_init((MppVencKcfg *)ref, MPP_VENC_KCFG_TYPE_REF_CFG); return mpp_enc_ref_cfg_init(ref); } MPP_RET mpp_enc_ref_cfg_deinit(MppEncRefCfg *ref) { if (!ref || !*ref) return MPP_ERR_VALUE; MPP_RET ret = kmpp_obj_put_f(*ref); *ref = NULL; return ret; } MPP_RET mpp_enc_ref_cfg_reset(MppEncRefCfg ref) { if (!ref) return MPP_ERR_VALUE; MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); MppEncRefStFrmCfg *st; rk_s32 vla_size = sizeof(MppEncRefStFrmCfg); rk_s32 ret; if (!cfg) return MPP_ERR_VALUE; /* restore default: st=1 simple forward reference */ cfg->keep_cpb = 0; cfg->new_st_cfg_cap = 1; cfg->new_lt_cfg_cap = 0; cfg->st_cfg_cap = 1; cfg->lt_cfg_cap = 0; cfg->st_cfg_cnt = 0; cfg->lt_cfg_cnt = 0; ret = kmpp_obj_resize_f(ref, vla_size); if (ret) { mpp_loge_f("resize to %d failed ret %d\n", vla_size, ret); return ret; } cfg = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); st = MPP_REF_ST_ARR(cfg); st[0].is_non_ref = 0; st[0].temporal_id = 0; st[0].ref_mode = REF_TO_PREV_REF_FRM; st[0].ref_arg = 0; st[0].repeat = 0; cfg->st_cfg_cnt = 1; cfg->max_tlayers = 1; cfg->ready = 1; memset(&cfg->cpb_info, 0, sizeof(cfg->cpb_info)); cfg->cpb_info.dpb_size = 1; cfg->cpb_info.max_st_cnt = 1; return MPP_OK; } MPP_RET mpp_enc_ref_cfg_set_cfg_cnt(MppEncRefCfg ref, RK_S32 lt_cnt, RK_S32 st_cnt) { return mpp_enc_ref_cfg_setup(ref, lt_cnt, st_cnt); } MPP_RET mpp_enc_ref_cfg_add_lt_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefLtFrmCfg *frm) { rk_s32 lt_cnt; rk_s32 lt_cap; rk_s32 i; rk_s32 j; if (!ref || !frm || cnt <= 0) return MPP_ERR_VALUE; if (!kmpp_obj_to_entry(ref)) return MPP_ERR_VALUE; kmpp_obj_get_s32(ref, "lt_cfg_cnt", <_cnt); kmpp_obj_get_s32(ref, "lt_cfg_cap", <_cap); if (lt_cnt + cnt > lt_cap) { mpp_loge_f("lt_cfg overflow cnt %d + add %d > cap %d\n", lt_cnt, cnt, lt_cap); return MPP_ERR_VALUE; } if (kmpp_obj_is_kobj(ref)) { KmppObjPos pos; kmpp_obj_pos_init(&pos); for (i = 0, j = lt_cnt; i < cnt; i++, j++) { /* seek by name only on the first element; NULL reuses the same array */ ENC_REF_POS_SEEK(ref, &pos, "lt_cfg", j, (i == 0) ? "lt_cfg" : NULL); ENC_REF_LT_POS_SET_FIELD(ref, &pos, j, lt_idx, frm[i].lt_idx); ENC_REF_LT_POS_SET_FIELD(ref, &pos, j, temporal_id, frm[i].temporal_id); ENC_REF_LT_POS_SET_FIELD(ref, &pos, j, ref_mode, frm[i].ref_mode); ENC_REF_LT_POS_SET_FIELD(ref, &pos, j, ref_arg, frm[i].ref_arg); ENC_REF_LT_POS_SET_FIELD(ref, &pos, j, lt_gap, frm[i].lt_gap); ENC_REF_LT_POS_SET_FIELD(ref, &pos, j, lt_delay, frm[i].lt_delay); } kmpp_obj_set_s32(ref, "lt_cfg_cnt", lt_cnt + cnt); } else { MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); memcpy(&MPP_REF_LT_ARR(cfg)[cfg->lt_cfg_cnt], frm, sizeof(*frm) * cnt); cfg->lt_cfg_cnt += cnt; } return MPP_OK; } MPP_RET mpp_enc_ref_cfg_add_st_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefStFrmCfg *frm) { rk_s32 st_cnt; rk_s32 st_cap; rk_s32 i; rk_s32 j; if (!ref || !frm || cnt <= 0) return MPP_ERR_VALUE; if (!kmpp_obj_to_entry(ref)) return MPP_ERR_VALUE; kmpp_obj_get_s32(ref, "st_cfg_cnt", &st_cnt); kmpp_obj_get_s32(ref, "st_cfg_cap", &st_cap); if (st_cnt + cnt > st_cap) { mpp_loge_f("st_cfg overflow cnt %d + add %d > cap %d\n", st_cnt, cnt, st_cap); return MPP_ERR_VALUE; } if (kmpp_obj_is_kobj(ref)) { KmppObjPos pos; kmpp_obj_pos_init(&pos); for (i = 0, j = st_cnt; i < cnt; i++, j++) { /* seek by name only on the first element; NULL reuses the same array */ ENC_REF_POS_SEEK(ref, &pos, "st_cfg", j, (i == 0) ? "st_cfg" : NULL); ENC_REF_ST_POS_SET_FIELD(ref, &pos, j, is_non_ref, frm[i].is_non_ref); ENC_REF_ST_POS_SET_FIELD(ref, &pos, j, temporal_id, frm[i].temporal_id); ENC_REF_ST_POS_SET_FIELD(ref, &pos, j, ref_mode, frm[i].ref_mode); ENC_REF_ST_POS_SET_FIELD(ref, &pos, j, ref_arg, frm[i].ref_arg); ENC_REF_ST_POS_SET_FIELD(ref, &pos, j, repeat, frm[i].repeat); } kmpp_obj_set_s32(ref, "st_cfg_cnt", st_cnt + cnt); } else { MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); memcpy(&MPP_REF_ST_ARR(cfg)[cfg->st_cfg_cnt], frm, sizeof(*frm) * cnt); cfg->st_cfg_cnt += cnt; } return MPP_OK; } MPP_RET mpp_enc_ref_cfg_check(MppEncRefCfg ref) { if (!ref) return MPP_ERR_VALUE; if (kmpp_obj_is_kobj((KmppObj)ref)) return kmpp_venc_ref_cfg_check((MppVencKcfg)ref); MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); RK_S32 lt_cfg_cnt = p->lt_cfg_cnt; RK_S32 st_cfg_cnt = p->st_cfg_cnt; RK_S32 max_lt_ref_cnt = 0; RK_S32 max_lt_ref_idx = 0; RK_S32 lt_idx_used_mask = 0; RK_S32 lt_dryrun_length = 0; RK_S32 max_st_ref_cnt = 0; RK_S32 max_st_tid = 0; RK_S32 st_tid_used_mask = 0; RK_S32 st_dryrun_length = 0; RK_S32 ready = 1; /* parse and check gop config for encoder */ if (lt_cfg_cnt) { RK_S32 pos; MppEncRefLtFrmCfg *lt_cfg = MPP_REF_LT_ARR(p); for (pos = 0; pos < lt_cfg_cnt; pos++) { MppEncRefLtFrmCfg *c = <_cfg[pos]; MppEncRefMode ref_mode = c->ref_mode; RK_S32 temporal_id = c->temporal_id; RK_S32 lt_idx = c->lt_idx; RK_U32 lt_idx_mask = 1 << lt_idx; /* check lt idx */ if (lt_idx >= MPP_ENC_MAX_LT_REF_NUM) { mpp_loge_f("ref cfg %p lt cfg %d with invalid lt_idx %d larger than MPP_ENC_MAX_LT_REF_NUM\n", ref, pos, lt_idx); ready = 0; } if (lt_idx_used_mask & lt_idx_mask) { mpp_loge_f("ref cfg %p lt cfg %d with redefined lt_idx %d config\n", ref, pos, lt_idx); ready = 0; } if (!(lt_idx_used_mask & lt_idx_mask)) { lt_idx_used_mask |= lt_idx_mask; max_lt_ref_cnt++; } if (lt_idx > max_lt_ref_idx) max_lt_ref_idx = lt_idx; /* check temporal id */ if (temporal_id != 0) { mpp_loge_f("ref cfg %p lt cfg %d with invalid temporal_id %d is non-zero\n", ref, pos, temporal_id); ready = 0; } /* check gop mode */ if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_LT_MODE(ref_mode)) { mpp_loge_f("ref cfg %p lt cfg %d with invalid ref mode %x\n", ref, pos, ref_mode); ready = 0; } /* if check failed just quit */ if (!ready) break; if (c->lt_gap && (c->lt_gap + c->lt_delay > lt_dryrun_length)) lt_dryrun_length = c->lt_gap + c->lt_delay; } } /* check st-ref config */ if (ready && st_cfg_cnt) { RK_S32 pos; MppEncRefStFrmCfg *st_cfg = MPP_REF_ST_ARR(p); for (pos = 0; pos < st_cfg_cnt; pos++) { MppEncRefStFrmCfg *c = &st_cfg[pos]; MppEncRefMode ref_mode = c->ref_mode; RK_S32 temporal_id = c->temporal_id; RK_U32 tid_mask = 1 << temporal_id; /* check temporal_id */ if (temporal_id > MPP_ENC_MAX_TEMPORAL_LAYER_NUM - 1) { mpp_loge_f("ref cfg %p st cfg %d with invalid temporal_id %d larger than MPP_ENC_MAX_TEMPORAL_LAYER_NUM\n", ref, pos, temporal_id); ready = 0; } /* check gop mode */ if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_ST_MODE(ref_mode)) { mpp_loge_f("ref cfg %p st cfg %d with invalid ref mode %x\n", ref, pos, ref_mode); ready = 0; } if (c->repeat < 0) { mpp_loge_f("ref cfg %p st cfg %d with negative repeat %d set to zero\n", ref, pos, c->repeat); c->repeat = 0; } /* constrain on head and tail frame */ if (pos == 0 || (pos == st_cfg_cnt - 1)) { if (c->is_non_ref) { mpp_loge_f("ref cfg %p st cfg %d with invalid non-ref frame on head/tail frame\n", ref, pos); ready = 0; } if (temporal_id > 0) { mpp_loge_f("ref cfg %p st cfg %d with invalid non-zero temporal id %d on head/tail frame\n", ref, pos, temporal_id); ready = 0; } } if (!ready) break; if (!c->is_non_ref && !(st_tid_used_mask & tid_mask)) { max_st_ref_cnt++; st_tid_used_mask |= tid_mask; } if (temporal_id > max_st_tid) max_st_tid = temporal_id; st_dryrun_length++; st_dryrun_length += c->repeat; } } if (ready) { MppEncCpbInfo *cpb_info = &p->cpb_info; MppEncRefs refs = NULL; MPP_RET ret = MPP_OK; p->max_tlayers = max_st_tid + 1; cpb_info->dpb_size = 0; cpb_info->max_lt_cnt = max_lt_ref_cnt; cpb_info->max_st_cnt = max_st_ref_cnt; cpb_info->max_lt_idx = max_lt_ref_idx; cpb_info->max_st_tid = max_st_tid; cpb_info->lt_gop = lt_dryrun_length; cpb_info->st_gop = st_dryrun_length - 1; ret = mpp_enc_refs_init(&refs); ready = (ret) ? 0 : (ready); ret = mpp_enc_refs_set_cfg(refs, ref); ready = (ret) ? 0 : (ready); ret = mpp_enc_refs_dryrun(refs); ready = (ret) ? 0 : (ready); /* update dpb size */ ret = mpp_enc_refs_get_cpb_info(refs, cpb_info); ready = (ret) ? 0 : (ready); ret = mpp_enc_refs_deinit(&refs); ready = (ret) ? 0 : (ready); } else { mpp_loge_f("check ref cfg %p failed\n", ref); } p->ready = ready; return ready ? MPP_OK : MPP_NOK; } MPP_RET mpp_enc_ref_cfg_set_keep_cpb(MppEncRefCfg ref, RK_S32 keep) { if (!ref) return MPP_ERR_VALUE; MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); if (!cfg) return MPP_ERR_VALUE; cfg->keep_cpb = keep; return MPP_OK; } void mpp_enc_ref_cfg_show(void) { KmppObjDef def = mpp_enc_ref_cfg_objdef(); MppTrie trie = kmpp_objdef_get_trie(def); MppTrieInfo *node; rk_s32 len; if (!trie) return; len = mpp_trie_get_name_max(trie); mpp_logi("dumping ref_cfg entries start\n"); node = mpp_trie_get_info_first(trie); while (node) { if (!mpp_trie_info_is_self(node) && node->ctx_len == sizeof(KmppEntry)) { KmppEntry *e = (KmppEntry *)mpp_trie_info_ctx(node); const char *name = mpp_trie_info_name(node); if (e->type == ENTRY_TYPE_VLA_INFO) mpp_logi("%-*s | vla | base%c %4d | size %4d | cnt%c %4d\n", len, name, e->vla.flex_base ? '@' : ' ', e->vla.base_off, e->vla.elem_size, e->vla.flex_count ? '@' : ' ', e->vla.flex_count ? e->vla.count_off : e->vla.elem_count); else mpp_logi("%-*s | %-6s | offset %4d | size %4d | flag %4x\n", len, name, strof_elem_type(e->tbl.elem_type), e->tbl.elem_offset, e->tbl.elem_size, e->tbl.flag_offset); } node = mpp_trie_get_info_next(trie, node); } mpp_logi("dumping ref_cfg entries done\n"); } static MPP_RET mpp_enc_ref_cfg_copy_k(MppEncRefCfg dst, MppEncRefCfg src) { rk_s32 lt_cap; rk_s32 st_cap; rk_s32 lt_cnt; rk_s32 st_cnt; rk_s32 keep_cpb; rk_s32 max_tlayers; rk_s32 ready; rk_s32 val; KmppObjPos pos; rk_s32 i; rk_s32 ret; /* read src caps and resize dst to match */ kmpp_obj_get_s32(src, "lt_cfg_cap", <_cap); kmpp_obj_get_s32(src, "st_cfg_cap", &st_cap); ret = ref_cfg_resize(dst, lt_cap, st_cap, __FUNCTION__); if (ret) return ret; /* read remaining src header scalars to copy */ kmpp_obj_get_s32(src, "lt_cfg_cnt", <_cnt); kmpp_obj_get_s32(src, "st_cfg_cnt", &st_cnt); kmpp_obj_get_s32(src, "keep_cpb", &keep_cpb); kmpp_obj_get_s32(src, "max_tlayers", &max_tlayers); kmpp_obj_get_s32(src, "ready", &ready); kmpp_obj_set_s32(dst, "lt_cfg_cnt", lt_cnt); kmpp_obj_set_s32(dst, "st_cfg_cnt", st_cnt); kmpp_obj_set_s32(dst, "keep_cpb", keep_cpb); kmpp_obj_set_s32(dst, "max_tlayers", max_tlayers); kmpp_obj_set_s32(dst, "ready", ready); /* copy st_cfg array elements field by field via schema */ for (i = 0; i < st_cnt; i++) { kmpp_obj_pos_init(&pos); ENC_REF_POS_SEEK(src, &pos, "st_cfg", i, (i == 0) ? "st_cfg" : NULL); ENC_REF_ST_POS_GET_FIELD(src, &pos, i, is_non_ref, &val); ENC_REF_ST_POS_SET_FIELD(dst, &pos, i, is_non_ref, val); ENC_REF_ST_POS_GET_FIELD(src, &pos, i, temporal_id, &val); ENC_REF_ST_POS_SET_FIELD(dst, &pos, i, temporal_id, val); ENC_REF_ST_POS_GET_FIELD(src, &pos, i, ref_mode, &val); ENC_REF_ST_POS_SET_FIELD(dst, &pos, i, ref_mode, val); ENC_REF_ST_POS_GET_FIELD(src, &pos, i, ref_arg, &val); ENC_REF_ST_POS_SET_FIELD(dst, &pos, i, ref_arg, val); ENC_REF_ST_POS_GET_FIELD(src, &pos, i, repeat, &val); ENC_REF_ST_POS_SET_FIELD(dst, &pos, i, repeat, val); } /* copy lt_cfg array elements field by field via schema */ for (i = 0; i < lt_cnt; i++) { kmpp_obj_pos_init(&pos); ENC_REF_POS_SEEK(src, &pos, "lt_cfg", i, (i == 0) ? "lt_cfg" : NULL); ENC_REF_LT_POS_GET_FIELD(src, &pos, i, lt_idx, &val); ENC_REF_LT_POS_SET_FIELD(dst, &pos, i, lt_idx, val); ENC_REF_LT_POS_GET_FIELD(src, &pos, i, temporal_id, &val); ENC_REF_LT_POS_SET_FIELD(dst, &pos, i, temporal_id, val); ENC_REF_LT_POS_GET_FIELD(src, &pos, i, ref_mode, &val); ENC_REF_LT_POS_SET_FIELD(dst, &pos, i, ref_mode, val); ENC_REF_LT_POS_GET_FIELD(src, &pos, i, ref_arg, &val); ENC_REF_LT_POS_SET_FIELD(dst, &pos, i, ref_arg, val); ENC_REF_LT_POS_GET_FIELD(src, &pos, i, lt_gap, &val); ENC_REF_LT_POS_SET_FIELD(dst, &pos, i, lt_gap, val); ENC_REF_LT_POS_GET_FIELD(src, &pos, i, lt_delay, &val); ENC_REF_LT_POS_SET_FIELD(dst, &pos, i, lt_delay, val); } return MPP_OK; } MPP_RET mpp_enc_ref_cfg_copy(MppEncRefCfg dst, MppEncRefCfg src) { rk_s32 src_kobj; rk_s32 dst_kobj; if (!dst || !src) return MPP_ERR_VALUE; if (!kmpp_obj_to_entry(src) || !kmpp_obj_to_entry(dst)) return MPP_ERR_VALUE; src_kobj = kmpp_obj_is_kobj((KmppObj)src); dst_kobj = kmpp_obj_is_kobj((KmppObj)dst); if (src_kobj != dst_kobj) { mpp_loge_f("src/dst kind mismatch: src_kobj %d dst_kobj %d\n", src_kobj, dst_kobj); return MPP_ERR_VALUE; } if (src_kobj) return mpp_enc_ref_cfg_copy_k(dst, src); MppEncRefCfgImpl *s = (MppEncRefCfgImpl *)kmpp_obj_to_entry(src); MppEncRefCfgImpl *d = (MppEncRefCfgImpl *)kmpp_obj_to_entry(dst); rk_s32 ret; ret = ref_cfg_resize(dst, s->lt_cfg_cap, s->st_cfg_cap, __FUNCTION__); if (ret) return ret; d = (MppEncRefCfgImpl *)kmpp_obj_to_entry(dst); /* copy header (offsets will be the same, overwrite is harmless) */ *d = *s; /* copy array data */ if (s->st_cfg_cnt) memcpy(MPP_REF_ST_ARR(d), MPP_REF_ST_ARR(s), s->st_cfg_cnt * sizeof(MppEncRefStFrmCfg)); if (s->lt_cfg_cnt) memcpy(MPP_REF_LT_ARR(d), MPP_REF_LT_ARR(s), s->lt_cfg_cnt * sizeof(MppEncRefLtFrmCfg)); return MPP_OK; } MppEncCpbInfo *mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref) { if (!ref) return NULL; MppEncRefCfgImpl *cfg = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); if (!cfg) return NULL; return &cfg->cpb_info; } /* * JSON config apply / extract — symmetric with mpp_enc_cfg_apply/extract */ MPP_RET mpp_enc_ref_cfg_apply(MppEncRefCfg ref, MppCfgStrFmt fmt, char *buf) { MppCfgObj root = NULL; MppEncRefCfgImpl *impl; MppCfgObj obj = NULL; RK_S32 st_cnt = 0; RK_S32 lt_cnt = 0; MPP_RET ret = MPP_NOK; if (!ref || !buf) return MPP_NOK; /* use the obj's own objdef so kobj entries carry kernel-layout offsets */ root = kmpp_objdef_get_cfg_root(kmpp_obj_to_objdef((KmppObj)ref)); if (!root) root = kmpp_objdef_get_cfg_root(mpp_enc_ref_cfg_def); impl = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); if (mpp_cfg_from_string(&obj, fmt, buf) || !obj) { mpp_loge_f("failed to parse config string\n"); mpp_cfg_put_all(obj); return MPP_NOK; } /* read VLA capacity from parsed tree before to_struct */ { MppCfgObj node = NULL; char st_cnt_name[] = "st_cfg_cnt"; char lt_cnt_name[] = "lt_cfg_cnt"; MppCfgVal val = { 0 }; if (mpp_cfg_find(&node, obj, st_cnt_name, fmt) || !node) { mpp_loge_f("failed to find st_cfg_cnt\n"); goto done; } if (mpp_cfg_get_val(node, MPP_CFG_TYPE_s32, &val)) { mpp_loge_f("failed to read st_cfg_cnt\n"); goto done; } st_cnt = val.s32; node = NULL; if (mpp_cfg_find(&node, obj, lt_cnt_name, fmt) || !node) { mpp_loge_f("failed to find lt_cfg_cnt\n"); goto done; } if (mpp_cfg_get_val(node, MPP_CFG_TYPE_s32, &val)) { mpp_loge_f("failed to read lt_cfg_cnt\n"); goto done; } lt_cnt = val.s32; } if (st_cnt < 0 || lt_cnt < 0 || st_cnt > MPP_ENC_MAX_REF_CFG_NUM || lt_cnt > MPP_ENC_MAX_REF_CFG_NUM) { mpp_loge_f("invalid count st %d lt %d (max %d)\n", st_cnt, lt_cnt, MPP_ENC_MAX_REF_CFG_NUM); goto done; } /* resize VLA to count from config */ if (st_cnt > impl->st_cfg_cap || lt_cnt > impl->lt_cfg_cap) { if (ref_cfg_resize(ref, lt_cnt, st_cnt, __FUNCTION__)) goto done; impl = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); } if (mpp_cfg_to_struct(obj, root, impl)) { mpp_loge_f("failed to convert config to struct\n"); goto done; } ret = mpp_enc_ref_cfg_check(ref); if (ret) { mpp_loge_f("ref cfg check failed\n"); if (impl->st_cfg_cap > 0) memset(MPP_REF_ST_ARR(impl), 0, impl->st_cfg_cap * sizeof(MppEncRefStFrmCfg)); if (impl->lt_cfg_cap > 0) memset(MPP_REF_LT_ARR(impl), 0, impl->lt_cfg_cap * sizeof(MppEncRefLtFrmCfg)); impl->st_cfg_cnt = 0; impl->lt_cfg_cnt = 0; } done: mpp_cfg_put_all(obj); return ret; } MPP_RET mpp_enc_ref_cfg_extract(MppEncRefCfg ref, MppCfgStrFmt fmt, char **buf) { MppEncRefCfgImpl *impl; MppCfgObj root; MppCfgObj obj = NULL; rk_s32 ret; if (!ref || !buf) return MPP_NOK; *buf = NULL; impl = (MppEncRefCfgImpl *)kmpp_obj_to_entry(ref); root = kmpp_objdef_get_cfg_root(kmpp_obj_to_objdef((KmppObj)ref)); if (!root) root = kmpp_objdef_get_cfg_root(mpp_enc_ref_cfg_def); ret = mpp_cfg_from_struct(&obj, root, impl); if (ret || !obj) { mpp_loge_f("failed to convert struct to config\n"); return MPP_NOK; } ret = mpp_cfg_to_string(obj, fmt, buf); if (ret) mpp_loge_f("failed to convert config to string\n"); mpp_cfg_put_all(obj); return *buf ? MPP_OK : MPP_NOK; }