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

322 lines
12 KiB
C

/* SPDX-License-Identifier: Apache-2.0 OR MIT */
/*
* Copyright (c) 2026 Rockchip Electronics Co., Ltd.
*/
#include <string.h>
#include "mpp_log.h"
#include "mpp_common.h"
#include "kmpp_obj.h"
#include "utils_singleton.h"
#include "mpp_enc_frm_cfg.h"
static rk_s32 mpp_enc_frm_cfg_impl_init(void *entry, KmppObj obj, const char *caller)
{
MppEncFrmCfg *e = (MppEncFrmCfg *)entry;
e->repeat = -1;
e->input_idr_req = -1;
e->input_pskip = -1;
e->input_pskip_non_ref = -1;
e->input_pskip_num = -1;
e->enc_mark_ltr = -1;
e->enc_use_ltr = -1;
e->enc_frame_qp = -1;
e->enc_base_layer_pid = -1;
e->temporal_id = -1;
(void)obj;
(void)caller;
return rk_ok;
}
static rk_s32 mpp_enc_frm_cfg_impl_resize(void *entry, KmppObj obj,
const char *caller)
{
MppEncFrmCfg *e = (MppEncFrmCfg *)entry;
KmppObjDef def = kmpp_obj_to_objdef(obj);
rk_u32 old_osd_off = e->osd_off;
rk_u32 old_jpeg_roi_off = e->jpeg_roi_off;
rk_s32 old_osd_cap = e->osd_cap;
rk_s32 old_jpeg_roi_cap = e->jpeg_roi_cap;
rk_s32 data_off;
(void)caller;
data_off = kmpp_objdef_get_entry_size(def) + kmpp_obj_to_flags_size(obj);
e->roi_off = data_off;
e->osd_off = data_off + e->new_roi_cap * sizeof(MppEncFrmRoi);
e->jpeg_roi_off = e->osd_off + e->new_osd_cap * sizeof(MppEncFrmOsd);
if (old_jpeg_roi_off && e->jpeg_roi_off != old_jpeg_roi_off &&
e->jpeg_roi_cnt > 0) {
rk_s32 move_cnt = MPP_MIN3((rk_s32)e->jpeg_roi_cnt,
e->new_jpeg_roi_cap,
old_jpeg_roi_cap);
if (move_cnt > 0)
memmove((char *)e + e->jpeg_roi_off,
(char *)e + old_jpeg_roi_off,
move_cnt * sizeof(MppEncFrmJpegRoi));
}
if (old_osd_off && e->osd_off != old_osd_off && e->osd_cnt > 0) {
rk_s32 move_cnt = MPP_MIN3((rk_s32)e->osd_cnt,
e->new_osd_cap, old_osd_cap);
if (move_cnt > 0)
memmove((char *)e + e->osd_off, (char *)e + old_osd_off,
move_cnt * sizeof(MppEncFrmOsd));
}
e->roi_cap = e->new_roi_cap;
e->osd_cap = e->new_osd_cap;
e->jpeg_roi_cap = e->new_jpeg_roi_cap;
return rk_ok;
}
#define MPP_ENC_FRM_CFG_ENTRY_TABLE(prefix, ENTRY, STRCT, EHOOK, SHOOK, ALIAS) \
CFG_DEF_START() \
ENTRY(prefix, s32, rk_s32, frame_idx, FLAG_NONE, frame_idx) \
ENTRY(prefix, s32, rk_s32, repeat, FLAG_NONE, repeat) \
ENTRY(prefix, s32, rk_s32, input_idr_req, FLAG_NONE, input_idr_req) \
ENTRY(prefix, s32, rk_s32, input_pskip, FLAG_NONE, input_pskip) \
ENTRY(prefix, s32, rk_s32, input_pskip_non_ref, FLAG_NONE, input_pskip_non_ref) \
ENTRY(prefix, s32, rk_s32, input_pskip_num, FLAG_NONE, input_pskip_num) \
ENTRY(prefix, s32, rk_s32, enc_mark_ltr, FLAG_NONE, enc_mark_ltr) \
ENTRY(prefix, s32, rk_s32, enc_use_ltr, FLAG_NONE, enc_use_ltr) \
ENTRY(prefix, s32, rk_s32, enc_frame_qp, FLAG_NONE, enc_frame_qp) \
ENTRY(prefix, s32, rk_s32, enc_base_layer_pid, FLAG_NONE, enc_base_layer_pid) \
ENTRY(prefix, s32, rk_s32, temporal_id, FLAG_NONE, temporal_id) \
ENTRY(prefix, u32, rk_u32, userdata, FLAG_NONE, userdata) \
ENTRY(prefix, u32, rk_u32, userdatas, FLAG_NONE, userdatas) \
ARRAY_START_FLEX_CNT_OFF(roi, MppEncFrmRoi, FLAG_NONE, roi_cnt, roi_off) \
ARRAY_ENTRY(s32, x, FLAG_NONE, x) \
ARRAY_ENTRY(s32, y, FLAG_NONE, y) \
ARRAY_ENTRY(s32, w, FLAG_NONE, w) \
ARRAY_ENTRY(s32, h, FLAG_NONE, h) \
ARRAY_ENTRY(s32, intra, FLAG_NONE, intra) \
ARRAY_ENTRY(s32, quality, FLAG_NONE, quality) \
ARRAY_ENTRY(s32, abs_qp_en, FLAG_NONE, abs_qp_en) \
ARRAY_END(roi) \
ENTRY(prefix, u32, rk_u32, jpeg_non_roi_level, FLAG_NONE, jpeg_non_roi_level) \
ENTRY(prefix, u32, rk_u32, jpeg_non_roi_en, FLAG_NONE, jpeg_non_roi_en) \
ARRAY_START_FLEX_CNT_OFF(jpeg_roi, MppEncFrmJpegRoi, FLAG_NONE, jpeg_roi_cnt, jpeg_roi_off) \
ARRAY_ENTRY(s32, x, FLAG_NONE, x) \
ARRAY_ENTRY(s32, y, FLAG_NONE, y) \
ARRAY_ENTRY(s32, w, FLAG_NONE, w) \
ARRAY_ENTRY(s32, h, FLAG_NONE, h) \
ARRAY_ENTRY(s32, level, FLAG_NONE, level) \
ARRAY_ENTRY(s32, roi_en, FLAG_NONE, roi_en) \
ARRAY_END(jpeg_roi) \
ARRAY_START_FLEX_CNT_OFF(osd, MppEncFrmOsd, FLAG_NONE, osd_cnt, osd_off) \
ARRAY_ENTRY(u32, enable, FLAG_NONE, enable) \
ARRAY_ENTRY(u32, range_trns_en, FLAG_NONE, range_trns_en) \
ARRAY_ENTRY(u32, range_trns_sel, FLAG_NONE, range_trns_sel) \
ARRAY_ENTRY(u32, fmt, FLAG_NONE, fmt) \
ARRAY_ENTRY(u32, rbuv_swap, FLAG_NONE, rbuv_swap) \
ARRAY_ENTRY(u32, lt_x, FLAG_NONE, lt_x) \
ARRAY_ENTRY(u32, lt_y, FLAG_NONE, lt_y) \
ARRAY_ENTRY(u32, rb_x, FLAG_NONE, rb_x) \
ARRAY_ENTRY(u32, rb_y, FLAG_NONE, rb_y) \
ARRAY_ENTRY(u32, stride, FLAG_NONE, stride) \
ARRAY_ENTRY(u32, ch_ds_mode, FLAG_NONE, ch_ds_mode) \
ARRAY_ENTRY(u32, osd_endn, FLAG_NONE, osd_endn) \
ARRAY_END(osd) \
CFG_DEF_END()
#define KMPP_OBJ_NAME mpp_enc_frm_cfg
#define KMPP_OBJ_INTF_TYPE MppEncFrmCfgObj
#define KMPP_OBJ_IMPL_TYPE MppEncFrmCfg
#define KMPP_OBJ_SGLN UTILS_SINGLETON
#define KMPP_OBJ_SGLN_ID UTILS_SGLN_ENC_FRM_CFG
#define KMPP_OBJ_FUNC_INIT mpp_enc_frm_cfg_impl_init
#define KMPP_OBJ_FUNC_RESIZE mpp_enc_frm_cfg_impl_resize
#define KMPP_OBJ_ENTRY_TABLE MPP_ENC_FRM_CFG_ENTRY_TABLE
#define KMPP_OBJ_HIERARCHY_ENABLE
#define KMPP_OBJ_FLEX_ENTRY_ENABLE
#include "kmpp_obj_helper.h"
static rk_s32 mpp_enc_frm_cfg_resize(MppEncFrmCfg *entry, KmppObj obj, rk_s32 roi_cnt,
rk_s32 osd_cnt, rk_s32 jpeg_roi_cnt,
const char *caller)
{
entry->new_roi_cap = MPP_MAX(roi_cnt, entry->roi_cap);
entry->new_osd_cap = MPP_MAX(osd_cnt, entry->osd_cap);
entry->new_jpeg_roi_cap = MPP_MAX(jpeg_roi_cnt, entry->jpeg_roi_cap);
return kmpp_obj_resize(obj,
entry->new_roi_cap * sizeof(MppEncFrmRoi) +
entry->new_osd_cap * sizeof(MppEncFrmOsd) +
entry->new_jpeg_roi_cap * sizeof(MppEncFrmJpegRoi), caller);
}
MPP_RET mpp_enc_frm_cfg_apply(MppEncFrmCfgObj obj, MppCfgStrFmt fmt, char *buf)
{
MppEncFrmCfg *entry = kmpp_obj_to_entry(obj);
MppCfgObj tree = NULL;
MppCfgObj root;
MPP_RET ret = MPP_NOK;
if (!obj || !buf)
return MPP_ERR_NULL_PTR;
root = kmpp_objdef_get_cfg_root(mpp_enc_frm_cfg_objdef());
if (mpp_cfg_from_string(&tree, fmt, buf) || !tree) {
mpp_cfg_put_all(tree);
return MPP_NOK;
}
/* read VLA counts from parsed tree before to_struct */
{
static char roi_cnt_name[] = "roi_cnt";
static char osd_cnt_name[] = "osd_cnt";
static char jpeg_roi_cnt_name[] = "jpeg_roi_cnt";
MppCfgObj node = NULL;
MppCfgVal val = { 0 };
rk_s32 roi_cnt = 0;
rk_s32 osd_cnt = 0;
rk_s32 jpeg_roi_cnt = 0;
if (mpp_cfg_find(&node, tree, roi_cnt_name, fmt) == 0 && node) {
if (mpp_cfg_get_val(node, MPP_CFG_TYPE_s32, &val) == 0)
roi_cnt = val.s32;
}
node = NULL;
val.s32 = 0;
if (mpp_cfg_find(&node, tree, osd_cnt_name, fmt) == 0 && node) {
if (mpp_cfg_get_val(node, MPP_CFG_TYPE_s32, &val) == 0)
osd_cnt = val.s32;
}
node = NULL;
val.s32 = 0;
if (mpp_cfg_find(&node, tree, jpeg_roi_cnt_name, fmt) == 0 && node) {
if (mpp_cfg_get_val(node, MPP_CFG_TYPE_s32, &val) == 0)
jpeg_roi_cnt = val.s32;
}
if (roi_cnt < 0 || roi_cnt > MPP_ENC_FRM_ROI_MAX_NUM ||
osd_cnt < 0 || osd_cnt > MPP_ENC_FRM_OSD_MAX_NUM ||
jpeg_roi_cnt < 0 || jpeg_roi_cnt > MPP_ENC_FRM_JPEG_ROI_MAX_NUM) {
mpp_loge_f("invalid array count roi %d osd %d jpeg_roi %d\n",
roi_cnt, osd_cnt, jpeg_roi_cnt);
goto done;
}
/* resize VLA if needed */
if (roi_cnt > entry->roi_cap || osd_cnt > entry->osd_cap ||
jpeg_roi_cnt > entry->jpeg_roi_cap) {
if (mpp_enc_frm_cfg_resize(entry, obj, roi_cnt, osd_cnt, jpeg_roi_cnt,
__FUNCTION__)) {
mpp_loge_f("resize to roi %d osd %d jpeg_roi %d failed\n",
roi_cnt, osd_cnt, jpeg_roi_cnt);
goto done;
}
entry = kmpp_obj_to_entry(obj);
}
}
if (mpp_cfg_to_struct(tree, root, entry)) {
mpp_loge_f("failed to convert config to struct\n");
goto done;
}
ret = MPP_OK;
done:
mpp_cfg_put_all(tree);
return ret;
}
MPP_RET mpp_enc_frm_cfg_extract(MppEncFrmCfgObj obj, MppCfgStrFmt fmt, char **buf)
{
MppEncFrmCfg *entry = kmpp_obj_to_entry(obj);
MppCfgObj tree = NULL;
MppCfgObj root;
if (!obj || !buf)
return MPP_ERR_NULL_PTR;
*buf = NULL;
root = kmpp_objdef_get_cfg_root(mpp_enc_frm_cfg_objdef());
if (mpp_cfg_from_struct(&tree, root, entry) || !tree)
return MPP_NOK;
mpp_cfg_to_string(tree, fmt, buf);
mpp_cfg_put_all(tree);
return *buf ? MPP_OK : MPP_NOK;
}
const MppEncFrmCfg *mpp_enc_frm_cfg_get_entry(MppEncFrmCfgObj obj)
{
if (!obj)
return NULL;
return kmpp_obj_to_entry(obj);
}
const MppEncFrmCfg *mpp_enc_frm_cfg_lookup(const MppEncFrmCfgSet *cfgs, rk_s32 frame_idx)
{
rk_u32 i;
if (!cfgs || !cfgs->entries || !cfgs->count)
return NULL;
for (i = 0; i < cfgs->count; i++) {
const MppEncFrmCfg *e = cfgs->entries[i];
if (!e)
continue;
if (e->repeat < 0 ||
(rk_s64)frame_idx <= (rk_s64)e->frame_idx + e->repeat) {
if (frame_idx >= e->frame_idx)
return e;
}
}
return NULL;
}
/* only one or two frames carry userdata: enough to verify the
* user/kernel boundary crossing without adding UD SEI to every frame.
* Optional scalars use -1 as the "not set" sentinel; leaving them at the
* C zero default would materialize them as real frame config (frame qp 0,
* non-IDR request, ...). */
static const MppEncFrmCfg mpp_enc_test_entries[] = {
{
.frame_idx = 0,
.repeat = 0,
.input_idr_req = -1,
.input_pskip = -1,
.input_pskip_non_ref = -1,
.input_pskip_num = -1,
.enc_mark_ltr = -1,
.enc_use_ltr = -1,
.enc_frame_qp = -1,
.enc_base_layer_pid = -1,
.temporal_id = -1,
.userdatas = 1,
},
{
.frame_idx = 1,
.repeat = 0,
.input_idr_req = -1,
.input_pskip = -1,
.input_pskip_non_ref = -1,
.input_pskip_num = -1,
.enc_mark_ltr = -1,
.enc_use_ltr = -1,
.enc_frame_qp = -1,
.enc_base_layer_pid = -1,
.temporal_id = -1,
.userdata = 1,
},
};
static const MppEncFrmCfg *mpp_enc_test_entry_ptrs[] = {
&mpp_enc_test_entries[0], &mpp_enc_test_entries[1],
};
const MppEncFrmCfgSet mpp_enc_test_frm_cfg = {
.count = MPP_ARRAY_ELEMS(mpp_enc_test_entry_ptrs),
.entries = mpp_enc_test_entry_ptrs,
};