[vepu540_gdr]: Support h264 intra refresh

Signed-off-by: Hongjin Li <vic.hong@rock-chips.com>
Change-Id: Ia30e11d29f24f82525ed675142dbdd42a07b4d6c
This commit is contained in:
Hongjin Li 2022-05-09 18:13:00 +08:00 committed by Herman Chen
parent 0ee683acf3
commit 962a88827b
7 changed files with 298 additions and 39 deletions

View file

@ -538,6 +538,20 @@ static MPP_RET h264e_proc_cfg(void *ctx, MpiCmd cmd, void *param)
if (src->prep.change)
ret |= h264e_proc_prep_cfg(&cfg->prep, &src->prep);
// TODO: rc cfg shouldn't be done here
if (cfg->rc.refresh_en) {
RK_U32 mb_rows;
if (MPP_ENC_RC_INTRA_REFRESH_ROW == cfg->rc.refresh_mode)
mb_rows = MPP_ALIGN(cfg->prep.height, 16) / 16;
else
mb_rows = MPP_ALIGN(cfg->prep.width, 16) / 16;
cfg->rc.refresh_length = (mb_rows + cfg->rc.refresh_num - 1) / cfg->rc.refresh_num;
if (cfg->rc.gop < cfg->rc.refresh_length)
cfg->rc.refresh_length = cfg->rc.gop;
}
if (src->codec.h264.change)
ret |= h264e_proc_h264_cfg(&cfg->codec.h264, &src->codec.h264);
@ -799,8 +813,11 @@ static MPP_RET h264e_sw_enc(void *ctx, HalEncTask *task)
MPP_RET h264e_add_sei(MppPacket pkt, RK_S32 *length, RK_U8 uuid[16],
const void *data, RK_S32 size)
{
return h264e_sei_to_packet(pkt, length, H264_SEI_USER_DATA_UNREGISTERED,
uuid, data, size);
if (uuid == uuid_refresh_cfg) {
return h264e_sei_recovery_point_to_packet(pkt, length, ((RK_U32 *)data)[0] - 1);
} else
return h264e_sei_to_packet(pkt, length, H264_SEI_USER_DATA_UNREGISTERED,
uuid, data, size);
}
/*!

View file

@ -27,6 +27,77 @@
#include "h264_syntax.h"
#include "h264e_sei.h"
static MPP_RET write_recovery_point(MppWriteCtx *bit, RK_U32 recovery_frame_cnt)
{
mpp_writer_put_ue(bit, recovery_frame_cnt);
mpp_writer_put_bits(bit, 1, 1);
mpp_writer_put_bits(bit, 0, 1);
mpp_writer_put_bits(bit, 0, 2);
mpp_writer_trailing(bit);
return MPP_OK;
}
MPP_RET h264e_sei_recovery_point_to_packet(MppPacket packet, RK_S32 *len, RK_U32 recovery_frame_cnt)
{
MPP_RET ret = MPP_OK;
void *pos = mpp_packet_get_pos(packet);
void *pkt_base = mpp_packet_get_data(packet);
size_t pkt_size = mpp_packet_get_size(packet);
size_t length = mpp_packet_get_length(packet);
void *dst = pos + length;
RK_S32 buf_size = (pkt_base + pkt_size) - (pos + length);
MppWriteCtx bit_ctx;
MppWriteCtx *bit = &bit_ctx;
RK_S32 payload_size = 0;
RK_S32 type = H264_SEI_RECOVERY_POINT;
RK_U8 src[100] = {0};
RK_S32 sei_size = 0;
RK_S32 i;
mpp_writer_init(bit, src, 100);
write_recovery_point(bit, recovery_frame_cnt);
payload_size = mpp_writer_bytes(bit);
mpp_writer_init(bit, dst, buf_size);
/* start_code_prefix 00 00 00 01 */
mpp_writer_put_raw_bits(bit, 0, 24);
mpp_writer_put_raw_bits(bit, 1, 8);
/* forbidden_zero_bit */
mpp_writer_put_raw_bits(bit, 0, 1);
/* nal_ref_idc */
mpp_writer_put_raw_bits(bit, H264_NALU_PRIORITY_DISPOSABLE, 2);
/* nal_unit_type */
mpp_writer_put_raw_bits(bit, H264_NALU_TYPE_SEI, 5);
/* sei_payload_type_ff_byte */
for (i = 0; i <= type - 255; i += 255)
mpp_writer_put_bits(bit, 0xff, 8);
/* sei_last_payload_type_byte */
mpp_writer_put_bits(bit, type - i, 8);
/* sei_payload_size_ff_byte */
for (i = 0; i <= payload_size - 255; i += 255)
mpp_writer_put_bits(bit, 0xff, 8);
/* sei_last_payload_size_byte */
mpp_writer_put_bits(bit, payload_size - i, 8);
write_recovery_point(bit, recovery_frame_cnt);
sei_size = mpp_writer_bytes(bit);
if (len)
*len = sei_size;
mpp_packet_set_length(packet, length + sei_size);
h264e_dbg_sei("sei data length %d pkt len %d -> %d\n", sei_size,
length, length + sei_size);
return ret;
}
MPP_RET h264e_sei_to_packet(MppPacket packet, RK_S32 *len, RK_S32 type,
RK_U8 uuid[16], const void *data, RK_S32 size)
{
@ -39,7 +110,7 @@ MPP_RET h264e_sei_to_packet(MppPacket packet, RK_S32 *len, RK_S32 type,
RK_S32 buf_size = (pkt_base + pkt_size) - (pos + length);
MppWriteCtx bit_ctx;
MppWriteCtx *bit = &bit_ctx;
RK_S32 uuid_size = 16;
RK_S32 uuid_size = uuid ? 16 : 0;
RK_S32 payload_size = size + uuid_size;
RK_S32 sei_size = 0;
RK_S32 i;

View file

@ -23,6 +23,7 @@
extern "C" {
#endif
MPP_RET h264e_sei_recovery_point_to_packet(MppPacket packet, RK_S32 *len, RK_U32 recovery_frame_cnt);
MPP_RET h264e_sei_to_packet(MppPacket packet, RK_S32 *len, RK_S32 type,
RK_U8 uuid[16], const void *data, RK_S32 size);

View file

@ -348,6 +348,66 @@ RK_S32 vepu541_get_roi_buf_size(RK_S32 w, RK_S32 h)
return buf_size + 32;
}
MPP_RET vepu541_set_one_roi(void *buf, MppEncROIRegion *region, RK_S32 w, RK_S32 h)
{
Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
RK_S32 mb_w = MPP_ALIGN(w, 16) / 16;
RK_S32 mb_h = MPP_ALIGN(h, 16) / 16;
RK_S32 stride_h = MPP_ALIGN(mb_w, 4);
Vepu541RoiCfg cfg;
MPP_RET ret = MPP_NOK;
if (NULL == buf || NULL == region) {
mpp_err_f("invalid buf %p roi %p\n", buf, region);
goto DONE;
}
RK_S32 roi_width = (region->w + 15) / 16;
RK_S32 roi_height = (region->h + 15) / 16;
RK_S32 pos_x_init = (region->x + 15) / 16;
RK_S32 pos_y_init = (region->y + 15) / 16;
RK_S32 pos_x_end = pos_x_init + roi_width;
RK_S32 pos_y_end = pos_y_init + roi_height;
RK_S32 x, y;
if (pos_x_end > mb_w)
pos_x_end = mb_w;
if (pos_y_end > mb_h)
pos_y_end = mb_h;
if (pos_x_init < 0)
pos_x_init = 0;
if (pos_y_init < 0)
pos_y_init = 0;
mpp_assert(pos_x_init >= 0 && pos_x_init < mb_w);
mpp_assert(pos_x_end >= 0 && pos_x_end <= mb_w);
mpp_assert(pos_y_init >= 0 && pos_y_init < mb_h);
mpp_assert(pos_y_end >= 0 && pos_y_end <= mb_h);
cfg.force_intra = region->intra;
cfg.reserved = 0;
cfg.qp_area_idx = region->qp_area_idx;
// NOTE: When roi is enabled the qp_area_en should be one.
cfg.qp_area_en = 1; // region->area_map_en;
cfg.qp_adj = region->quality;
cfg.qp_adj_mode = region->abs_qp_en;
ptr += pos_y_init * stride_h + pos_x_init;
for (y = 0; y < roi_height; y++) {
Vepu541RoiCfg *dst = ptr;
for (x = 0; x < roi_width; x++, dst++)
memcpy(dst, &cfg, sizeof(cfg));
ptr += stride_h;
}
DONE:
return ret;
}
MPP_RET vepu541_set_roi(void *buf, MppEncROICfg *roi, RK_S32 w, RK_S32 h)
{
MppEncROIRegion *region = roi->regions;
@ -415,37 +475,7 @@ MPP_RET vepu541_set_roi(void *buf, MppEncROICfg *roi, RK_S32 w, RK_S32 h)
region = roi->regions;
/* step 2. setup region for top to bottom */
for (i = 0; i < (RK_S32)roi->number; i++, region++) {
RK_S32 roi_width = (region->w + 15) / 16;
RK_S32 roi_height = (region->h + 15) / 16;
RK_S32 pos_x_init = (region->x + 15) / 16;
RK_S32 pos_y_init = (region->y + 15) / 16;
RK_S32 pos_x_end = pos_x_init + roi_width;
RK_S32 pos_y_end = pos_y_init + roi_height;
RK_S32 x, y;
mpp_assert(pos_x_init >= 0 && pos_x_init < mb_w);
mpp_assert(pos_x_end >= 0 && pos_x_end <= mb_w);
mpp_assert(pos_y_init >= 0 && pos_y_init < mb_h);
mpp_assert(pos_y_end >= 0 && pos_y_end <= mb_h);
cfg.force_intra = region->intra;
cfg.reserved = 0;
cfg.qp_area_idx = region->qp_area_idx;
// NOTE: When roi is enabled the qp_area_en should be one.
cfg.qp_area_en = 1; // region->area_map_en;
cfg.qp_adj = region->quality;
cfg.qp_adj_mode = region->abs_qp_en;
ptr = (Vepu541RoiCfg *)buf;
ptr += pos_y_init * stride_h + pos_x_init;
for (y = 0; y < roi_height; y++) {
Vepu541RoiCfg *dst = ptr;
for (x = 0; x < roi_width; x++, dst++)
memcpy(dst, &cfg, sizeof(cfg));
ptr += stride_h;
}
vepu541_set_one_roi(buf, region, w, h);
}
DONE:

View file

@ -174,6 +174,7 @@ MPP_RET vepu541_set_fmt(VepuFmtCfg *cfg, MppFrameFormat format);
*/
RK_S32 vepu541_get_roi_buf_size(RK_S32 w, RK_S32 h);
MPP_RET vepu541_set_roi(void *buf, MppEncROICfg *roi, RK_S32 w, RK_S32 h);
MPP_RET vepu541_set_one_roi(void *buf, MppEncROIRegion *region, RK_S32 w, RK_S32 h);
MPP_RET vepu541_set_osd(Vepu541OsdCfg *cfg);
MPP_RET vepu540_set_osd(Vepu541OsdCfg *cfg);

View file

@ -963,6 +963,96 @@ static void setup_vepu541_io_buf(Vepu541H264eRegSet *regs, MppDev dev,
hal_h264e_dbg_func("leave\n");
}
static MPP_RET setup_vepu541_intra_refresh(Vepu541H264eRegSet *regs, HalH264eVepu541Ctx *ctx, RK_U32 refresh_idx)
{
MPP_RET ret = MPP_OK;
RK_U32 w = ctx->sps->pic_width_in_mbs * 16;
RK_U32 h = ctx->sps->pic_height_in_mbs * 16;
MppEncROIRegion *region = NULL;
RK_U32 refresh_num = ctx->cfg->rc.refresh_num;
RK_U32 stride_h = MPP_ALIGN(w / 16, 4);
RK_U32 stride_v = MPP_ALIGN(h / 16, 4);
RK_U32 i = 0;
hal_h264e_dbg_func("enter\n");
if (!ctx->cfg->rc.refresh_en) {
ret = MPP_ERR_VALUE;
goto RET;
}
if (NULL == ctx->roi_buf) {
RK_S32 roi_buf_size = vepu541_get_roi_buf_size(w, h);
if (NULL == ctx->roi_grp)
mpp_buffer_group_get_internal(&ctx->roi_grp, MPP_BUFFER_TYPE_ION);
mpp_buffer_get(ctx->roi_grp, &ctx->roi_buf, roi_buf_size);
ctx->roi_buf_size = roi_buf_size;
}
mpp_assert(ctx->roi_buf);
RK_S32 fd = mpp_buffer_get_fd(ctx->roi_buf);
void *buf = mpp_buffer_get_ptr(ctx->roi_buf);
Vepu541RoiCfg cfg;
Vepu541RoiCfg *ptr = (Vepu541RoiCfg *)buf;
cfg.force_intra = 0;
cfg.reserved = 0;
cfg.qp_area_idx = 0;
cfg.qp_area_en = 1;
cfg.qp_adj = 0;
cfg.qp_adj_mode = 0;
for (i = 0; i < stride_h * stride_v; i++, ptr++)
memcpy(ptr, &cfg, sizeof(cfg));
region = mpp_calloc(MppEncROIRegion, 1);
if (NULL == region) {
mpp_err_f("Failed to calloc for MppEncROIRegion !\n");
ret = MPP_ERR_MALLOC;
}
if (ctx->cfg->rc.refresh_mode == MPP_ENC_RC_INTRA_REFRESH_ROW) {
region->x = 0;
region->w = w;
if (refresh_idx > 0) {
region->y = refresh_idx * 16 * refresh_num - 32;
region->h = 16 * refresh_num + 32;
} else {
region->y = refresh_idx * 16 * refresh_num;
region->h = 16 * refresh_num;
}
regs->reg089.cme_srch_v = 1;
} else if (ctx->cfg->rc.refresh_mode == MPP_ENC_RC_INTRA_REFRESH_COL) {
region->y = 0;
region->h = h;
if (refresh_idx > 0) {
region->x = refresh_idx * 16 * refresh_num - 32;
region->w = 16 * refresh_num + 32;
} else {
region->x = refresh_idx * 16 * refresh_num;
region->w = 16 * refresh_num;
}
regs->reg089.cme_srch_h = 1;
}
region->intra = 1;
region->quality = -ctx->cfg->rc.qp_delta_ip;
region->area_map_en = 1;
region->qp_area_idx = 1;
region->abs_qp_en = 0;
regs->reg013.roi_enc = 1;
regs->reg073.roi_addr = fd;
vepu541_set_one_roi(buf, region, w, h);
mpp_free(region);
RET:
hal_h264e_dbg_func("leave, ret %d\n", ret);
return ret;
}
static void setup_vepu541_roi(Vepu541H264eRegSet *regs, HalH264eVepu541Ctx *ctx)
{
@ -1457,6 +1547,7 @@ static MPP_RET hal_h264e_vepu541_gen_regs(void *hal, HalEncTask *task)
H264ePps *pps = ctx->pps;
H264eSlice *slice = ctx->slice;
MPP_RET ret = MPP_OK;
EncFrmStatus *frm_status = &task->rc_task->frm;
hal_h264e_dbg_func("enter %p\n", hal);
hal_h264e_dbg_detail("frame %d generate regs now", ctx->frms->seq_idx);
@ -1488,6 +1579,9 @@ static MPP_RET hal_h264e_vepu541_gen_regs(void *hal, HalEncTask *task)
setup_vepu541_me(regs, sps, slice, ctx->is_vepu540);
if (frm_status->is_i_refresh)
setup_vepu541_intra_refresh(regs, ctx, frm_status->seq_idx % cfg->rc.gop);
if (ctx->is_vepu540)
vepu540_set_osd(&ctx->osd_cfg);
else

View file

@ -281,6 +281,55 @@ static RK_S32 setup_output_packet(HalH264eVepu2Ctx *ctx, RK_U32 *reg, MppBuffer
return (offset - offset8) * 8;
}
static MPP_RET setup_intra_refresh(HalH264eVepu2Ctx *ctx, EncFrmStatus *frm)
{
MPP_RET ret = MPP_OK;
RK_U32 mb_w = ctx->sps->pic_width_in_mbs;
RK_U32 mb_h = ctx->sps->pic_height_in_mbs;
RK_U32 refresh_num = ctx->cfg->rc.refresh_num;
MppEncCfgSet *cfg = ctx->cfg;
RK_U32 *reg = ctx->regs_set.val;
RK_U32 val = 0;
RK_S32 top = 0;
RK_S32 left = 0;
RK_S32 right = 0;
RK_S32 bottom = 0;
RK_U32 refresh_idx = frm->seq_idx % cfg->rc.gop;
hal_h264e_dbg_func("enter\n");
if (!ctx->cfg->rc.refresh_en || !frm->is_i_refresh) {
goto RET;
}
if (ctx->cfg->rc.refresh_mode == MPP_ENC_RC_INTRA_REFRESH_ROW) {
left = 0;
right = mb_w;
top = refresh_idx * refresh_num - 2;
bottom = (refresh_idx + 1) * refresh_num - 1;
top = mpp_clip(top, 0, mb_h);
bottom = mpp_clip(bottom, 0, mb_h);
} else if (ctx->cfg->rc.refresh_mode == MPP_ENC_RC_INTRA_REFRESH_COL) {
top = 0;
bottom = mb_h;
left = refresh_idx * refresh_num - 2;
right = (refresh_idx + 1) * refresh_num - 1;
left = mpp_clip(left, 0, mb_w);
right = mpp_clip(right, 0, mb_w);
}
RET:
val = VEPU_REG_INTRA_AREA_TOP(top)
| VEPU_REG_INTRA_AREA_BOTTOM(bottom)
| VEPU_REG_INTRA_AREA_LEFT(left)
| VEPU_REG_INTRA_AREA_RIGHT(right);
H264E_HAL_SET_REG(reg, VEPU_REG_INTRA_AREA_CTRL, val);
hal_h264e_dbg_func("leave, ret %d\n", ret);
return ret;
}
static MPP_RET hal_h264e_vepu2_gen_regs_v2(void *hal, HalEncTask *task)
{
//MPP_RET ret = MPP_OK;
@ -333,11 +382,7 @@ static MPP_RET hal_h264e_vepu2_gen_regs_v2(void *hal, HalEncTask *task)
* values of other planes are calculated internally based on
* format setting.
*/
val = VEPU_REG_INTRA_AREA_TOP(mb_h)
| VEPU_REG_INTRA_AREA_BOTTOM(mb_h)
| VEPU_REG_INTRA_AREA_LEFT(mb_w)
| VEPU_REG_INTRA_AREA_RIGHT(mb_w);
H264E_HAL_SET_REG(reg, VEPU_REG_INTRA_AREA_CTRL, val);
setup_intra_refresh(ctx, frm);
val = VEPU_REG_AXI_CTRL_READ_ID(0);
val |= VEPU_REG_AXI_CTRL_WRITE_ID(0);