singe/thirdparty/rockchip-mpp/mpp/base/mpp_enc_ref.c
2026-09-10 20:17:28 -05:00

902 lines
30 KiB
C

/* SPDX-License-Identifier: Apache-2.0 OR MIT */
/*
* Copyright (c) 2015 Rockchip Electronics Co., Ltd.
*/
#define MODULE_TAG "mpp_enc_ref"
#include <string.h>
#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", &lt_cnt);
kmpp_obj_get_s32(ref, "lt_cfg_cap", &lt_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 = &lt_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", &lt_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", &lt_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;
}