805 lines
25 KiB
C
805 lines
25 KiB
C
/* SPDX-License-Identifier: Apache-2.0 OR MIT */
|
|
/*
|
|
* Copyright (c) 2026 Rockchip Electronics Co., Ltd.
|
|
*/
|
|
|
|
#define MODULE_TAG "kmpp_venc_utils"
|
|
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#include "mpp_log.h"
|
|
#include "mpp_env.h"
|
|
#include "rk_venc_cmd.h"
|
|
|
|
#include "kmpp_meta.h"
|
|
#include "kmpp_obj.h"
|
|
#include "mpp_common.h"
|
|
#include "kmpp_venc_utils.h"
|
|
|
|
static RK_U32 venc_utils_debug = 0;
|
|
|
|
#define venc_utils_dbg(fmt, ...) \
|
|
mpp_logi_c(venc_utils_debug, fmt, ## __VA_ARGS__)
|
|
|
|
#define MPP_ENC_FRM_JPEG_ROI_LEVEL_MAX 63
|
|
|
|
/* Standard test UUID for unregistered user data SEI */
|
|
RK_U8 venc_test_uuid[16] = {
|
|
0xfe, 0x39, 0xac, 0x4c, 0x4a, 0x8e, 0x4b, 0x4b,
|
|
0x85, 0xd9, 0xb2, 0xa2, 0x4f, 0xa1, 0x19, 0x5b,
|
|
};
|
|
|
|
static int find_nal_start(const RK_U8 *data, RK_S32 len, RK_S32 *offset)
|
|
{
|
|
RK_S32 i = *offset;
|
|
RK_S32 zeros = 0;
|
|
|
|
for (; i < len - 2; i++) {
|
|
if (data[i] == 0) {
|
|
zeros++;
|
|
} else if (data[i] == 1 && zeros >= 2) {
|
|
*offset = i + 1;
|
|
return (zeros >= 3) ? 4 : 3;
|
|
} else {
|
|
zeros = 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
RK_S32 kmpp_venc_scan_sei_userdata(const RK_U8 *data, RK_S32 len, const char *expect, RK_S32 expect_len)
|
|
{
|
|
RK_S32 offset = 0;
|
|
|
|
while (offset < len - 4) {
|
|
if (!find_nal_start(data, len, &offset) || offset >= len)
|
|
break;
|
|
|
|
/* check SEI NAL type */
|
|
if ((data[offset] & 0x1F) != 6)
|
|
continue;
|
|
|
|
/* parse SEI payload_type and payload_size */
|
|
{
|
|
RK_S32 pos = offset + 1;
|
|
RK_S32 payload_type = 0;
|
|
RK_S32 payload_size = 0;
|
|
|
|
while (pos < len && data[pos] == 0xff) {
|
|
payload_type += 255;
|
|
pos++;
|
|
}
|
|
if (pos < len) {
|
|
payload_type += data[pos];
|
|
pos++;
|
|
}
|
|
|
|
if (payload_type != 5)
|
|
continue;
|
|
|
|
while (pos < len && data[pos] == 0xff) {
|
|
payload_size += 255;
|
|
pos++;
|
|
}
|
|
if (pos < len) {
|
|
payload_size += data[pos];
|
|
pos++;
|
|
}
|
|
|
|
/* check UUID match */
|
|
if (pos + 16 > len)
|
|
break;
|
|
|
|
if (memcmp(data + pos, venc_test_uuid, 16) != 0)
|
|
continue;
|
|
|
|
pos += 16;
|
|
|
|
/* verify payload content */
|
|
{
|
|
RK_S32 ud_len = payload_size - 16;
|
|
|
|
if (ud_len <= 0 || pos + ud_len > len)
|
|
break;
|
|
|
|
if (ud_len >= expect_len && memcmp(data + pos, expect, expect_len) == 0)
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
MPP_RET kmpp_venc_gen_userdata(KmppMeta meta, RK_U8 *ud_buf, RK_U32 ud_buf_size)
|
|
{
|
|
MppEncUserDataShm ud;
|
|
|
|
if (!meta || !ud_buf || !ud_buf_size)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
memset(&ud, 0, sizeof(ud));
|
|
ud.len = ud_buf_size;
|
|
ud.data.uptr = ud_buf;
|
|
|
|
if (kmpp_meta_set_ptr(meta, KEY_USER_DATA, &ud))
|
|
mpp_loge("KEY_USER_DATA not set, skipped\n");
|
|
venc_utils_dbg("set KEY_USER_DATA len %d\n", ud_buf_size);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET kmpp_venc_gen_userdatas(KmppMeta meta, const RK_U8 *uuid,
|
|
RK_U8 *ud_buf, RK_U32 ud_buf_size)
|
|
{
|
|
MPP_ENC_UDS1(uds_s);
|
|
MppEncUserDataFullShm *entry = uds_s.set.data;
|
|
RK_U8 uuid_buf[MPP_ENC_USER_DATA_UUID_LEN];
|
|
|
|
if (!meta || !ud_buf || !ud_buf_size)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
memset(&uds_s, 0, sizeof(uds_s));
|
|
uds_s.set.count = 1;
|
|
entry->len = ud_buf_size;
|
|
if (uuid) {
|
|
memcpy(uuid_buf, uuid, sizeof(uuid_buf));
|
|
entry->uuid.uptr = uuid_buf;
|
|
}
|
|
entry->data.uptr = ud_buf;
|
|
|
|
if (kmpp_meta_set_ptr(meta, KEY_USER_DATAS, &uds_s.set))
|
|
mpp_loge("KEY_USER_DATAS not set, skipped\n");
|
|
venc_utils_dbg("set KEY_USER_DATAS len %d\n", ud_buf_size);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
/*
|
|
* Convert Q16 fixed-point ratio to pixel coordinate.
|
|
*
|
|
* px = (ratio * size) >> 16, clamped to [0, size - 1].
|
|
* Ratio >= COORD_MAX maps to size - 1 (edge of frame), negative maps to 0.
|
|
*/
|
|
static RK_U32 frm_cfg_px(RK_S32 ratio, RK_U32 size)
|
|
{
|
|
RK_U32 px;
|
|
|
|
if (size <= 0)
|
|
return 0;
|
|
|
|
if (ratio <= 0)
|
|
return 0;
|
|
|
|
if (ratio >= MPP_ENC_FRM_CFG_COORD_MAX)
|
|
return size - 1;
|
|
|
|
/* (ratio * size) <= (2^16 - 1) * size, 32-bit safe up to 64K picture */
|
|
px = (RK_U32)(ratio * (RK_S32)size) >> 16;
|
|
|
|
if (px >= size)
|
|
px = size - 1;
|
|
|
|
return px;
|
|
}
|
|
|
|
MPP_RET kmpp_venc_gen_roi(KmppMeta meta, RK_U32 w, RK_U32 h,
|
|
RK_U32 roi_cnt, const MppEncFrmRoi *roi)
|
|
{
|
|
MppEncROICfgLegacy cfg = { .change = 1 };
|
|
RK_U32 i;
|
|
|
|
if (!meta || !roi || !roi_cnt || roi_cnt > 8)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
cfg.number = roi_cnt;
|
|
for (i = 0; i < roi_cnt; i++) {
|
|
if (roi[i].x < 0 || roi[i].x > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
roi[i].y < 0 || roi[i].y > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
roi[i].w <= 0 || roi[i].w > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
roi[i].h <= 0 || roi[i].h > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
roi[i].intra < 0 || roi[i].intra > USHRT_MAX ||
|
|
roi[i].quality < SHRT_MIN || roi[i].quality > SHRT_MAX ||
|
|
roi[i].abs_qp_en < 0 || roi[i].abs_qp_en > UCHAR_MAX)
|
|
return MPP_ERR_VALUE;
|
|
RK_U32 x = frm_cfg_px(roi[i].x, w);
|
|
RK_U32 y = frm_cfg_px(roi[i].y, h);
|
|
RK_U32 rw = frm_cfg_px(roi[i].w, w);
|
|
RK_U32 rh = frm_cfg_px(roi[i].h, h);
|
|
|
|
/* clamp: region must stay inside frame, kernel rejects x+w > w */
|
|
if (x + rw > w)
|
|
rw = w - x;
|
|
if (y + rh > h)
|
|
rh = h - y;
|
|
|
|
cfg.regions[i].x = (RK_U16)x;
|
|
cfg.regions[i].y = (RK_U16)y;
|
|
cfg.regions[i].w = (RK_U16)rw;
|
|
cfg.regions[i].h = (RK_U16)rh;
|
|
cfg.regions[i].intra = (RK_U16)roi[i].intra;
|
|
cfg.regions[i].quality = (RK_S16)roi[i].quality;
|
|
cfg.regions[i].abs_qp_en = (RK_U8)roi[i].abs_qp_en;
|
|
}
|
|
|
|
kmpp_meta_set_ptr(meta, KEY_ROI_DATA, &cfg);
|
|
venc_utils_dbg("ROI cnt=%d r0=(%d,%d,%dx%d) i=%d q=%d\n",
|
|
roi_cnt, cfg.regions[0].x, cfg.regions[0].y,
|
|
cfg.regions[0].w, cfg.regions[0].h,
|
|
cfg.regions[0].intra, cfg.regions[0].quality);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
/*
|
|
* Auto-derive OSD stride from region width and format when stride == 0.
|
|
* Pixel bytes per format matches vepu5xx_check_osd_buffer_size.
|
|
*/
|
|
static RK_U32 frm_cfg_osd_stride(RK_U32 width, RK_U32 fmt)
|
|
{
|
|
RK_U32 ret = width;
|
|
|
|
switch (fmt) {
|
|
case MPP_FMT_ARGB8888 :
|
|
case MPP_FMT_ABGR8888 :
|
|
case MPP_FMT_BGRA8888 :
|
|
case MPP_FMT_RGBA8888 : {
|
|
ret = width * 4;
|
|
} break;
|
|
case MPP_FMT_ARGB1555 :
|
|
case MPP_FMT_RGB565 :
|
|
case MPP_FMT_BGR565 : {
|
|
ret = width * 2;
|
|
} break;
|
|
default : {
|
|
} break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET kmpp_venc_gen_osd(KmppMeta meta, RK_U32 w, RK_U32 h,
|
|
RK_U32 osd_cnt, const MppEncFrmOsd *osd)
|
|
{
|
|
MppEncOSDData3 data = { .change = 1 };
|
|
RK_U32 i;
|
|
|
|
if (!meta || !osd || !osd_cnt || osd_cnt > 8)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
data.num_region = osd_cnt;
|
|
for (i = 0; i < osd_cnt && i < 8; i++) {
|
|
RK_U32 lt_x = frm_cfg_px(osd[i].lt_x, w);
|
|
RK_U32 lt_y = frm_cfg_px(osd[i].lt_y, h);
|
|
RK_U32 rb_x = frm_cfg_px(osd[i].rb_x, w);
|
|
RK_U32 rb_y = frm_cfg_px(osd[i].rb_y, h);
|
|
|
|
/* clamp: rb corner must be after lt corner, inside frame */
|
|
if (rb_x < lt_x)
|
|
rb_x = lt_x;
|
|
if (rb_y < lt_y)
|
|
rb_y = lt_y;
|
|
|
|
data.region[i].enable = osd[i].enable;
|
|
data.region[i].range_trns_en = osd[i].range_trns_en;
|
|
data.region[i].range_trns_sel = osd[i].range_trns_sel;
|
|
data.region[i].fmt = osd[i].fmt;
|
|
data.region[i].rbuv_swap = osd[i].rbuv_swap;
|
|
data.region[i].lt_x = lt_x;
|
|
data.region[i].lt_y = lt_y;
|
|
data.region[i].rb_x = rb_x;
|
|
data.region[i].rb_y = rb_y;
|
|
data.region[i].stride = osd[i].stride ? osd[i].stride :
|
|
frm_cfg_osd_stride(rb_x - lt_x + 1, osd[i].fmt);
|
|
data.region[i].ch_ds_mode = osd[i].ch_ds_mode;
|
|
data.region[i].osd_endn = osd[i].osd_endn;
|
|
}
|
|
|
|
kmpp_meta_set_ptr(meta, KEY_OSD_DATA4, &data);
|
|
venc_utils_dbg("OSD cnt=%d r0=(%d,%d)-(%d,%d)\n",
|
|
osd_cnt, data.region[0].lt_x, data.region[0].lt_y,
|
|
data.region[0].rb_x, data.region[0].rb_y);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
static void set_scalar_or_skip(KmppMeta meta, RK_S32 key, RK_S32 val)
|
|
{
|
|
if (val >= 0 && kmpp_meta_set_s32(meta, key, val))
|
|
venc_utils_dbg("frame scalar key %#08x not set, skipped\n", key);
|
|
}
|
|
|
|
static MPP_RET mpp_venc_check_frame_scalars(const MppEncFrmCfg *entry)
|
|
{
|
|
if (entry->input_idr_req < -1 || entry->input_idr_req > 1 ||
|
|
entry->input_pskip < -1 || entry->input_pskip > 1 ||
|
|
entry->input_pskip_non_ref < -1 || entry->input_pskip_non_ref > 1 ||
|
|
entry->input_pskip_num < -1 ||
|
|
entry->enc_mark_ltr < -1 || entry->enc_use_ltr < -1 ||
|
|
entry->enc_frame_qp < -1 || entry->enc_frame_qp > 51 ||
|
|
entry->enc_base_layer_pid < -1 || entry->temporal_id < -1 ||
|
|
(entry->input_pskip > 0 && entry->input_pskip_non_ref > 0))
|
|
return MPP_ERR_VALUE;
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
static MPP_RET kmpp_venc_set_frame_scalars(KmppMeta meta, const MppEncFrmCfg *entry)
|
|
{
|
|
if (entry->input_pskip > 0 && entry->input_pskip_non_ref > 0) {
|
|
mpp_loge_f("pskip and pskip_non_ref cannot coexist\n");
|
|
return MPP_ERR_VALUE;
|
|
}
|
|
|
|
set_scalar_or_skip(meta, KEY_INPUT_IDR_REQ, entry->input_idr_req);
|
|
set_scalar_or_skip(meta, KEY_INPUT_PSKIP, entry->input_pskip);
|
|
set_scalar_or_skip(meta, KEY_INPUT_PSKIP_NON_REF, entry->input_pskip_non_ref);
|
|
set_scalar_or_skip(meta, KEY_INPUT_PSKIP_NUM, entry->input_pskip_num);
|
|
set_scalar_or_skip(meta, KEY_ENC_MARK_LTR, entry->enc_mark_ltr);
|
|
set_scalar_or_skip(meta, KEY_ENC_USE_LTR, entry->enc_use_ltr);
|
|
set_scalar_or_skip(meta, KEY_ENC_FRAME_QP, entry->enc_frame_qp);
|
|
set_scalar_or_skip(meta, KEY_ENC_BASE_LAYER_PID, entry->enc_base_layer_pid);
|
|
set_scalar_or_skip(meta, KEY_TEMPORAL_ID, entry->temporal_id);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
static MPP_RET kmpp_venc_gen_jpeg_roi(KmppMeta meta, RK_U32 w, RK_U32 h,
|
|
RK_U32 jpeg_roi_cnt,
|
|
const MppEncFrmJpegRoi *jpeg_roi,
|
|
RK_U32 non_roi_level, RK_U32 non_roi_en)
|
|
{
|
|
MppJpegROICfg cfg = { .change = 1 };
|
|
RK_U32 i;
|
|
|
|
if (!meta || !jpeg_roi || !jpeg_roi_cnt)
|
|
return MPP_ERR_NULL_PTR;
|
|
if (jpeg_roi_cnt > MPP_ARRAY_ELEMS(cfg.regions) ||
|
|
non_roi_level > MPP_ENC_FRM_JPEG_ROI_LEVEL_MAX ||
|
|
non_roi_en > 1)
|
|
return MPP_ERR_VALUE;
|
|
|
|
cfg.non_roi_level = non_roi_level;
|
|
cfg.non_roi_en = non_roi_en;
|
|
for (i = 0; i < jpeg_roi_cnt; i++) {
|
|
const MppEncFrmJpegRoi *src = &jpeg_roi[i];
|
|
|
|
if (src->x < 0 || src->x > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->y < 0 || src->y > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->w <= 0 || src->w > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->h <= 0 || src->h > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->level < 0 ||
|
|
src->level > MPP_ENC_FRM_JPEG_ROI_LEVEL_MAX ||
|
|
src->roi_en < 0 || src->roi_en > 1)
|
|
return MPP_ERR_VALUE;
|
|
|
|
cfg.regions[i].x = frm_cfg_px(src->x, w);
|
|
cfg.regions[i].y = frm_cfg_px(src->y, h);
|
|
cfg.regions[i].w = frm_cfg_px(src->w, w);
|
|
cfg.regions[i].h = frm_cfg_px(src->h, h);
|
|
cfg.regions[i].level = src->level;
|
|
cfg.regions[i].roi_en = src->roi_en;
|
|
}
|
|
|
|
return kmpp_meta_set_ptr(meta, KEY_JPEG_ROI_DATA, &cfg);
|
|
}
|
|
|
|
MPP_RET kmpp_venc_gen_frame_meta(KmppMeta meta, RK_U32 w, RK_U32 h,
|
|
const MppEncFrmCfg *entry)
|
|
{
|
|
MPP_RET ret = MPP_OK;
|
|
|
|
if (!meta || !entry)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
mpp_env_get_u32("kmpp_venc_utils_debug", &venc_utils_debug, 0);
|
|
|
|
ret = mpp_venc_check_frame_scalars(entry);
|
|
if (ret)
|
|
return ret;
|
|
ret = kmpp_venc_set_frame_scalars(meta, entry);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (entry->userdatas) {
|
|
const RK_U8 *uds_uuid = entry->ud_uuid ? entry->ud_uuid : venc_test_uuid;
|
|
|
|
ret = kmpp_venc_gen_userdatas(meta, uds_uuid, entry->ud_buf, entry->ud_buf_size);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->userdata) {
|
|
ret = kmpp_venc_gen_userdata(meta, entry->ud_buf, entry->ud_buf_size);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->roi_cnt) {
|
|
ret = kmpp_venc_gen_roi(meta, w, h, entry->roi_cnt, MPP_ENC_FRM_ROI_ARR(entry));
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->osd_cnt) {
|
|
ret = kmpp_venc_gen_osd(meta, w, h, entry->osd_cnt, MPP_ENC_FRM_OSD_ARR(entry));
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->jpeg_roi_cnt) {
|
|
ret = kmpp_venc_gen_jpeg_roi(meta, w, h, entry->jpeg_roi_cnt,
|
|
MPP_ENC_FRM_JPEG_ROI_ARR(entry),
|
|
entry->jpeg_non_roi_level,
|
|
entry->jpeg_non_roi_en);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
void mpp_venc_frm_meta_deinit(MppEncFrmMetaData *data)
|
|
{
|
|
RK_U32 i;
|
|
|
|
if (!data)
|
|
return;
|
|
|
|
for (i = 0; i < MPP_ARRAY_ELEMS(data->osd_buffers); i++) {
|
|
if (data->osd_buffers[i]) {
|
|
kmpp_buffer_put(data->osd_buffers[i]);
|
|
data->osd_buffers[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static RK_U32 mpp_venc_osd_min_stride(RK_U32 fmt, RK_U32 width)
|
|
{
|
|
switch (fmt) {
|
|
case MPP_FMT_ARGB8888 :
|
|
case MPP_FMT_ABGR8888 :
|
|
case MPP_FMT_BGRA8888 :
|
|
case MPP_FMT_RGBA8888 :
|
|
return width * 4;
|
|
case MPP_FMT_ARGB1555 :
|
|
case MPP_FMT_RGB565 :
|
|
case MPP_FMT_BGR565 :
|
|
return width * 2;
|
|
default :
|
|
mpp_loge_f("unsupported osd format %d\n", fmt);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static MPP_RET mpp_venc_prepare_roi(MppEncFrmMetaData *data, RK_U32 w, RK_U32 h,
|
|
RK_U32 roi_cnt, const MppEncFrmRoi *src)
|
|
{
|
|
RK_U32 i;
|
|
|
|
if (roi_cnt > MPP_ARRAY_ELEMS(data->roi_regions))
|
|
return MPP_ERR_VALUE;
|
|
|
|
data->roi.number = roi_cnt;
|
|
data->roi.regions = data->roi_regions;
|
|
for (i = 0; i < roi_cnt; i++) {
|
|
if (src[i].x < 0 || src[i].x > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].y < 0 || src[i].y > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].w <= 0 || src[i].w > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].h <= 0 || src[i].h > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].intra < 0 || src[i].intra > USHRT_MAX ||
|
|
src[i].quality < SHRT_MIN || src[i].quality > SHRT_MAX ||
|
|
src[i].abs_qp_en < 0 || src[i].abs_qp_en > UCHAR_MAX)
|
|
return MPP_ERR_VALUE;
|
|
RK_U32 x = frm_cfg_px(src[i].x, w);
|
|
RK_U32 y = frm_cfg_px(src[i].y, h);
|
|
RK_U32 rw = frm_cfg_px(src[i].w, w);
|
|
RK_U32 rh = frm_cfg_px(src[i].h, h);
|
|
|
|
if (x + rw > w) rw = w - x;
|
|
if (y + rh > h) rh = h - y;
|
|
|
|
data->roi_regions[i].x = x;
|
|
data->roi_regions[i].y = y;
|
|
data->roi_regions[i].w = rw;
|
|
data->roi_regions[i].h = rh;
|
|
data->roi_regions[i].intra = src[i].intra;
|
|
data->roi_regions[i].quality = src[i].quality;
|
|
data->roi_regions[i].qp_area_idx = 0;
|
|
data->roi_regions[i].area_map_en = 1;
|
|
data->roi_regions[i].abs_qp_en = src[i].abs_qp_en;
|
|
}
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
static MPP_RET mpp_venc_prepare_osd(MppEncFrmMetaData *data, RK_U32 w, RK_U32 h,
|
|
RK_U32 osd_cnt, const MppEncFrmOsd *src)
|
|
{
|
|
RK_U32 i;
|
|
|
|
mpp_venc_frm_meta_deinit(data);
|
|
memset(data->osd_buffers, 0, sizeof(data->osd_buffers));
|
|
memset(&data->osd, 0, sizeof(data->osd));
|
|
if (!osd_cnt)
|
|
return MPP_OK;
|
|
if (osd_cnt > MPP_ARRAY_ELEMS(data->osd.region))
|
|
return MPP_ERR_VALUE;
|
|
|
|
data->osd.change = 1;
|
|
data->osd.num_region = osd_cnt;
|
|
for (i = 0; i < osd_cnt; i++) {
|
|
MppEncOSDRegion3 *dst = &data->osd.region[i];
|
|
RK_U32 lt_x, lt_y, rb_x, rb_y;
|
|
RK_U32 width, height, min_stride;
|
|
RK_U64 size;
|
|
RK_U32 stride;
|
|
|
|
if (src[i].lt_x > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].lt_y > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].rb_x > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].rb_y > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src[i].rb_x < src[i].lt_x || src[i].rb_y < src[i].lt_y)
|
|
goto fail;
|
|
|
|
lt_x = frm_cfg_px(src[i].lt_x, w);
|
|
lt_y = frm_cfg_px(src[i].lt_y, h);
|
|
rb_x = frm_cfg_px(src[i].rb_x, w);
|
|
rb_y = frm_cfg_px(src[i].rb_y, h);
|
|
|
|
width = rb_x - lt_x + 1;
|
|
height = rb_y - lt_y + 1;
|
|
min_stride = mpp_venc_osd_min_stride(src[i].fmt, width);
|
|
if (!min_stride)
|
|
goto fail;
|
|
stride = src[i].stride ? src[i].stride : min_stride;
|
|
if (stride < min_stride)
|
|
goto fail;
|
|
size = (RK_U64)stride * height;
|
|
if (!size || size > INT_MAX)
|
|
goto fail;
|
|
|
|
dst->enable = src[i].enable;
|
|
dst->range_trns_en = src[i].range_trns_en;
|
|
dst->range_trns_sel = src[i].range_trns_sel;
|
|
dst->fmt = src[i].fmt;
|
|
dst->rbuv_swap = src[i].rbuv_swap;
|
|
dst->lt_x = lt_x;
|
|
dst->lt_y = lt_y;
|
|
dst->rb_x = rb_x;
|
|
dst->rb_y = rb_y;
|
|
dst->stride = stride;
|
|
dst->ch_ds_mode = src[i].ch_ds_mode;
|
|
dst->osd_endn = src[i].osd_endn;
|
|
|
|
dst->lut[0] = 0x80;
|
|
dst->lut[1] = 0x80;
|
|
dst->lut[2] = 0;
|
|
dst->lut[3] = 0x80;
|
|
dst->lut[4] = 0x80;
|
|
dst->lut[5] = 0xff;
|
|
|
|
{
|
|
KmppBufCfg bcfg;
|
|
KmppShmPtr sptr;
|
|
MPP_RET ret;
|
|
|
|
ret = kmpp_buffer_get(&data->osd_buffers[i]);
|
|
if (ret || !data->osd_buffers[i]) {
|
|
data->osd_buffers[i] = NULL;
|
|
goto fail;
|
|
}
|
|
bcfg = kmpp_buffer_to_cfg(data->osd_buffers[i]);
|
|
if (!bcfg) {
|
|
kmpp_buffer_put(data->osd_buffers[i]);
|
|
data->osd_buffers[i] = NULL;
|
|
goto fail;
|
|
}
|
|
if (kmpp_buf_cfg_set_size(bcfg, MPP_ALIGN((RK_U32)size, 16)) ||
|
|
kmpp_buffer_setup(data->osd_buffers[i]) ||
|
|
kmpp_buf_cfg_get_sptr(bcfg, &sptr) || !sptr.uptr)
|
|
goto fail;
|
|
memset(sptr.uptr, 0xff - i * 0x11, (size_t)size);
|
|
dst->osd_buf = *kmpp_obj_to_shm(data->osd_buffers[i]);
|
|
}
|
|
}
|
|
|
|
return MPP_OK;
|
|
|
|
fail:
|
|
mpp_venc_frm_meta_deinit(data);
|
|
memset(data->osd_buffers, 0, sizeof(data->osd_buffers));
|
|
memset(&data->osd, 0, sizeof(data->osd));
|
|
return MPP_ERR_VALUE;
|
|
}
|
|
|
|
MPP_RET mpp_venc_gen_userdata(MppMeta meta, RK_U8 *ud_buf, RK_U32 ud_buf_size)
|
|
{
|
|
MppEncUserData user_data = { .len = ud_buf_size, .pdata = ud_buf };
|
|
|
|
if (!meta || !ud_buf || !ud_buf_size)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
return mpp_meta_set_ptr(meta, KEY_USER_DATA, &user_data);
|
|
}
|
|
|
|
MPP_RET mpp_venc_gen_userdatas(MppMeta meta, const RK_U8 *uuid,
|
|
RK_U8 *ud_buf, RK_U32 ud_buf_size)
|
|
{
|
|
MppEncUserDataFull user_data = {
|
|
.len = ud_buf_size,
|
|
.uuid = (RK_U8 *)uuid,
|
|
.pdata = ud_buf,
|
|
};
|
|
MppEncUserDataSet set = { .count = 1, .datas = &user_data };
|
|
|
|
if (!meta || !ud_buf || !ud_buf_size)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
return mpp_meta_set_ptr(meta, KEY_USER_DATAS, &set);
|
|
}
|
|
|
|
static void set_mpp_scalar_or_skip(MppMeta meta, RK_S32 key, RK_S32 val)
|
|
{
|
|
if (val >= 0 && mpp_meta_set_s32(meta, key, val))
|
|
venc_utils_dbg("frame scalar key %#08x not set, skipped\n", key);
|
|
}
|
|
|
|
static MPP_RET mpp_venc_set_frame_scalars_mpp(MppMeta meta, const MppEncFrmCfg *entry)
|
|
{
|
|
if (entry->input_pskip > 0 && entry->input_pskip_non_ref > 0) {
|
|
mpp_loge_f("pskip and pskip_non_ref cannot coexist\n");
|
|
return MPP_ERR_VALUE;
|
|
}
|
|
|
|
set_mpp_scalar_or_skip(meta, KEY_INPUT_IDR_REQ, entry->input_idr_req);
|
|
set_mpp_scalar_or_skip(meta, KEY_INPUT_PSKIP, entry->input_pskip);
|
|
set_mpp_scalar_or_skip(meta, KEY_INPUT_PSKIP_NON_REF, entry->input_pskip_non_ref);
|
|
set_mpp_scalar_or_skip(meta, KEY_INPUT_PSKIP_NUM, entry->input_pskip_num);
|
|
set_mpp_scalar_or_skip(meta, KEY_ENC_MARK_LTR, entry->enc_mark_ltr);
|
|
set_mpp_scalar_or_skip(meta, KEY_ENC_USE_LTR, entry->enc_use_ltr);
|
|
set_mpp_scalar_or_skip(meta, KEY_ENC_FRAME_QP, entry->enc_frame_qp);
|
|
set_mpp_scalar_or_skip(meta, KEY_ENC_BASE_LAYER_PID, entry->enc_base_layer_pid);
|
|
set_mpp_scalar_or_skip(meta, KEY_TEMPORAL_ID, entry->temporal_id);
|
|
|
|
return MPP_OK;
|
|
}
|
|
|
|
MPP_RET mpp_venc_gen_roi(MppMeta meta, RK_U32 w, RK_U32 h,
|
|
RK_U32 roi_cnt, const MppEncFrmRoi *roi,
|
|
MppEncFrmMetaData *data)
|
|
{
|
|
MPP_RET ret;
|
|
|
|
if (!meta || !roi || !roi_cnt || !data)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
ret = mpp_venc_prepare_roi(data, w, h, roi_cnt, roi);
|
|
if (!ret)
|
|
ret = mpp_meta_set_ptr(meta, KEY_ROI_DATA, &data->roi);
|
|
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET mpp_venc_gen_osd(MppMeta meta, RK_U32 w, RK_U32 h,
|
|
RK_U32 osd_cnt, const MppEncFrmOsd *osd,
|
|
MppEncFrmMetaData *data)
|
|
{
|
|
MPP_RET ret;
|
|
|
|
if (!meta || !osd || !osd_cnt || !data)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
ret = mpp_venc_prepare_osd(data, w, h, osd_cnt, osd);
|
|
if (!ret)
|
|
ret = mpp_meta_set_ptr(meta, KEY_OSD_DATA3, &data->osd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
MPP_RET mpp_venc_gen_jpeg_roi(MppMeta meta, RK_U32 w, RK_U32 h,
|
|
RK_U32 jpeg_roi_cnt,
|
|
const MppEncFrmJpegRoi *jpeg_roi,
|
|
RK_U32 non_roi_level, RK_U32 non_roi_en,
|
|
MppEncFrmMetaData *data)
|
|
{
|
|
MppJpegROICfg *cfg;
|
|
RK_U32 i;
|
|
|
|
if (!meta || !jpeg_roi || !jpeg_roi_cnt || !data)
|
|
return MPP_ERR_NULL_PTR;
|
|
cfg = &data->jpeg_roi;
|
|
if (jpeg_roi_cnt > MPP_ARRAY_ELEMS(cfg->regions) ||
|
|
non_roi_level > MPP_ENC_FRM_JPEG_ROI_LEVEL_MAX ||
|
|
non_roi_en > 1)
|
|
return MPP_ERR_VALUE;
|
|
|
|
memset(cfg, 0, sizeof(*cfg));
|
|
cfg->change = 1;
|
|
cfg->non_roi_level = non_roi_level;
|
|
cfg->non_roi_en = non_roi_en;
|
|
for (i = 0; i < jpeg_roi_cnt; i++) {
|
|
const MppEncFrmJpegRoi *src = &jpeg_roi[i];
|
|
|
|
if (src->x < 0 || src->x > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->y < 0 || src->y > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->w <= 0 || src->w > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->h <= 0 || src->h > MPP_ENC_FRM_CFG_COORD_MAX ||
|
|
src->level < 0 ||
|
|
src->level > MPP_ENC_FRM_JPEG_ROI_LEVEL_MAX ||
|
|
src->roi_en < 0 || src->roi_en > 1)
|
|
return MPP_ERR_VALUE;
|
|
|
|
cfg->regions[i].x = frm_cfg_px(src->x, w);
|
|
cfg->regions[i].y = frm_cfg_px(src->y, h);
|
|
cfg->regions[i].w = frm_cfg_px(src->w, w);
|
|
cfg->regions[i].h = frm_cfg_px(src->h, h);
|
|
cfg->regions[i].level = src->level;
|
|
cfg->regions[i].roi_en = src->roi_en;
|
|
}
|
|
|
|
return mpp_meta_set_ptr(meta, KEY_JPEG_ROI_DATA, cfg);
|
|
}
|
|
|
|
MPP_RET mpp_venc_gen_frame_meta(MppMeta meta, RK_U32 w, RK_U32 h,
|
|
const MppEncFrmCfg *entry,
|
|
MppEncFrmMetaData *data)
|
|
{
|
|
RK_U8 *ud_buf;
|
|
RK_U32 ud_buf_size;
|
|
MPP_RET ret;
|
|
|
|
if (!meta || !entry || !data)
|
|
return MPP_ERR_NULL_PTR;
|
|
|
|
ret = mpp_venc_check_frame_scalars(entry);
|
|
if (ret)
|
|
return ret;
|
|
ret = mpp_venc_set_frame_scalars_mpp(meta, entry);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ud_buf = entry->ud_buf ? entry->ud_buf : data->ud_buf;
|
|
ud_buf_size = entry->ud_buf ? entry->ud_buf_size : data->ud_buf_size;
|
|
|
|
if (entry->userdatas) {
|
|
const RK_U8 *uds_uuid = entry->ud_uuid ? entry->ud_uuid : venc_test_uuid;
|
|
|
|
ret = mpp_venc_gen_userdatas(meta, uds_uuid, ud_buf, ud_buf_size);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->userdata) {
|
|
ret = mpp_venc_gen_userdata(meta, ud_buf, ud_buf_size);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->roi_cnt) {
|
|
ret = mpp_venc_gen_roi(meta, w, h, entry->roi_cnt,
|
|
MPP_ENC_FRM_ROI_ARR(entry), data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->osd_cnt) {
|
|
ret = mpp_venc_gen_osd(meta, w, h, entry->osd_cnt,
|
|
MPP_ENC_FRM_OSD_ARR(entry), data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (entry->jpeg_roi_cnt) {
|
|
ret = mpp_venc_gen_jpeg_roi(meta, w, h, entry->jpeg_roi_cnt,
|
|
MPP_ENC_FRM_JPEG_ROI_ARR(entry),
|
|
entry->jpeg_non_roi_level,
|
|
entry->jpeg_non_roi_en, data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return MPP_OK;
|
|
}
|