322 lines
12 KiB
C
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,
|
|
};
|