From 0a2d4e341cd032eced293b09fb40e94c84668365 Mon Sep 17 00:00:00 2001 From: Herman Chen Date: Mon, 30 Mar 2020 15:25:27 +0800 Subject: [PATCH] [mpp_enc_v2]: Add encoder header output mode 1. Default output mode is output header only on config changed. 2. Add new mode to output header on each intra frame. Signed-off-by: Herman Chen Change-Id: Iea8dd1e6bb377318b88300d6a013f2c736b15afc --- inc/rk_mpi_cmd.h | 2 + inc/rk_venc_cmd.h | 15 ++--- mpp/codec/mpp_enc_debug.h | 2 + mpp/codec/mpp_enc_v2.cpp | 128 ++++++++++++++++++++++++++----------- mpp/hal/inc/hal_enc_task.h | 3 + 5 files changed, 105 insertions(+), 45 deletions(-) diff --git a/inc/rk_mpi_cmd.h b/inc/rk_mpi_cmd.h index 3a503737..4ad19e14 100644 --- a/inc/rk_mpi_cmd.h +++ b/inc/rk_mpi_cmd.h @@ -164,6 +164,8 @@ typedef enum { MPP_ENC_CFG_MJPEG = CMD_MODULE_CODEC | CMD_CTX_ID_ENC | CMD_ENC_CFG_MJPEG, MPP_ENC_CFG_MISC = CMD_MODULE_CODEC | CMD_CTX_ID_ENC | CMD_ENC_CFG_MISC, + MPP_ENC_SET_HEADER_MODE, /* set MppEncHeaderMode */ + MPP_ENC_GET_HEADER_MODE, /* get MppEncHeaderMode */ MPP_ENC_CFG_SPLIT = CMD_MODULE_CODEC | CMD_CTX_ID_ENC | CMD_ENC_CFG_SPLIT, MPP_ENC_SET_SPLIT, /* set MppEncSliceSplit structure */ diff --git a/inc/rk_venc_cmd.h b/inc/rk_venc_cmd.h index 20a29d5c..b0dc695c 100644 --- a/inc/rk_venc_cmd.h +++ b/inc/rk_venc_cmd.h @@ -394,14 +394,13 @@ typedef struct MppEncMDBlkInfo_t { RK_S32 mvy : 8; /* bit 24~31 - signed vertical mv */ } MppEncMDBlkInfo; -/* - * Mpp video codec related configuration - */ -typedef struct MppEncHwCfg_t { - RK_U32 change; - RK_S32 me_search_range_x; - RK_S32 me_search_range_y; -} MppEncHwCfg; +typedef enum MppEncHeaderMode_t { + /* default mode: attach vps/sps/pps only on first frame */ + MPP_ENC_HEADER_MODE_DEFAULT, + /* IDR mode: attach vps/sps/pps on each IDR frame */ + MPP_ENC_HEADER_MODE_EACH_IDR, + MPP_ENC_HEADER_MODE_BUTT, +} MppEncHeaderMode; typedef enum MppEncSeiMode_t { MPP_ENC_SEI_MODE_DISABLE, /* default mode, SEI writing is disabled */ diff --git a/mpp/codec/mpp_enc_debug.h b/mpp/codec/mpp_enc_debug.h index d190949f..dce093b5 100644 --- a/mpp/codec/mpp_enc_debug.h +++ b/mpp/codec/mpp_enc_debug.h @@ -25,6 +25,7 @@ #define MPP_ENC_DBG_DETAIL (0x00000020) #define MPP_ENC_DBG_RESET (0x00000040) #define MPP_ENC_DBG_NOTIFY (0x00000080) +#define MPP_ENC_DBG_REENC (0x00000100) #define mpp_enc_dbg(flag, fmt, ...) _mpp_dbg(mpp_enc_debug, flag, fmt, ## __VA_ARGS__) #define mpp_enc_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_enc_debug, flag, fmt, ## __VA_ARGS__) @@ -34,6 +35,7 @@ #define enc_dbg_status(fmt, ...) mpp_enc_dbg_f(MPP_ENC_DBG_STATUS, fmt, ## __VA_ARGS__) #define enc_dbg_detail(fmt, ...) mpp_enc_dbg_f(MPP_ENC_DBG_DETAIL, fmt, ## __VA_ARGS__) #define enc_dbg_notify(fmt, ...) mpp_enc_dbg_f(MPP_ENC_DBG_NOTIFY, fmt, ## __VA_ARGS__) +#define enc_dbg_reenc(fmt, ...) mpp_enc_dbg_f(MPP_ENC_DBG_REENC, fmt, ## __VA_ARGS__) extern RK_U32 mpp_enc_debug; diff --git a/mpp/codec/mpp_enc_v2.cpp b/mpp/codec/mpp_enc_v2.cpp index 6ac00dfa..9b301f78 100644 --- a/mpp/codec/mpp_enc_v2.cpp +++ b/mpp/codec/mpp_enc_v2.cpp @@ -75,16 +75,18 @@ typedef struct MppEncImpl_t { MppEncCfgSet set; /* control process */ + RK_U32 cmd_send; + RK_U32 cmd_recv; MpiCmd cmd; void *param; + MPP_RET *cmd_ret; sem_t enc_ctrl; // legacy support for MPP_ENC_GET_EXTRA_INFO MppPacket hdr_pkt; - - RK_U32 cmd_send; - RK_U32 cmd_recv; - RK_U32 hdr_need_updated; + RK_U32 hdr_len; + RK_U32 hdr_ready; + MppEncHeaderMode hdr_mode; } MppEncImpl; typedef union EncTaskWait_u { @@ -120,6 +122,7 @@ typedef union EncTaskStatus_u { RK_U32 task_out_rdy : 1; RK_U32 rc_check_frm_drop : 1; // rc stage + RK_U32 enc_add_header : 1; // write header before encoding RK_U32 enc_backup : 1; // enc stage RK_U32 enc_restore : 1; // reenc flow start point RK_U32 enc_proc_dpb : 1; // enc stage @@ -235,8 +238,6 @@ static void mpp_enc_proc_cfg(MppEncImpl *enc) switch (enc->cmd) { case MPP_ENC_GET_HDR_SYNC : case MPP_ENC_GET_EXTRA_INFO : { - MppPacket pkt = NULL; - /* * NOTE: get stream header should use user's MppPacket * If we provide internal MppPacket to external user @@ -244,23 +245,20 @@ static void mpp_enc_proc_cfg(MppEncImpl *enc) * So encoder always write its header to external buffer * which is provided by user. */ + if (!enc->hdr_ready) { + enc_impl_gen_hdr(enc->impl, enc->hdr_pkt); + enc->hdr_len = mpp_packet_get_length(enc->hdr_pkt); + enc->hdr_ready = 1; + } + if (enc->cmd == MPP_ENC_GET_EXTRA_INFO) { mpp_err("Please use MPP_ENC_GET_HDR_SYNC instead of unsafe MPP_ENC_GET_EXTRA_INFO\n"); + mpp_err("NOTE: MPP_ENC_GET_HDR_SYNC needs MppPacket input\n"); - if (NULL == enc->hdr_pkt) { - size_t size = SZ_1K; - void *ptr = mpp_calloc_size(void, size); - - mpp_packet_init(&enc->hdr_pkt, ptr, size); - } - pkt = enc->hdr_pkt; - *(MppPacket *)enc->param = pkt; - } else - pkt = (MppPacket)enc->param; - - enc_impl_gen_hdr(enc->impl, pkt); - - enc->hdr_need_updated = 0; + *(MppPacket *)enc->param = enc->hdr_pkt; + } else { + mpp_packet_copy((MppPacket)enc->param, enc->hdr_pkt); + } } break; case MPP_ENC_GET_RC_API_ALL : { RcApiQueryAll *query = (RcApiQueryAll *)enc->param; @@ -290,11 +288,28 @@ static void mpp_enc_proc_cfg(MppEncImpl *enc) enc->rc_status.rc_api_user_cfg = 1; enc->rc_status.rc_api_updated = 1; } break; + case MPP_ENC_SET_HEADER_MODE : { + if (enc->param) { + MppEncHeaderMode mode = *((MppEncHeaderMode *)enc->param); + + if (mode < MPP_ENC_HEADER_MODE_BUTT) { + enc->hdr_mode = mode; + enc_dbg_ctrl("header mode set to %d\n", mode); + } else { + mpp_err_f("invalid header mode %d\n", mode); + *enc->cmd_ret = MPP_NOK; + } + } else { + mpp_err_f("invalid NULL ptr on setting header mode\n"); + *enc->cmd_ret = MPP_NOK; + } + } break; default : { enc_impl_proc_cfg(enc->impl, enc->cmd, enc->param); if (MPP_ENC_SET_CODEC_CFG == enc->cmd || - MPP_ENC_SET_PREP_CFG == enc->cmd) - enc->hdr_need_updated = 1; + MPP_ENC_SET_PREP_CFG == enc->cmd) { + enc->hdr_ready = 0; + } } break; } } @@ -610,23 +625,34 @@ void *mpp_enc_thread(void *data) // 11. check frame drop by frame rate conversion RUN_ENC_RC_FUNC(rc_frm_check_drop, enc->rc_ctx, rc_task, mpp, ret); + task.status.rc_check_frm_drop = 1; enc_dbg_detail("task %d drop %d\n", frm->seq_idx, frm->drop); + + // when the frame should be dropped just return empty packet if (frm->drop) { hal_task->valid = 0; hal_task->length = 0; goto TASK_DONE; } + + // start encoder task process here hal_task->valid = 1; // 12. generate header before hardware stream - if (enc->hdr_need_updated) { - enc_impl_gen_hdr(impl, packet); - enc->hdr_need_updated = 0; + if (!enc->hdr_ready) { + enc_impl_gen_hdr(impl, enc->hdr_pkt); + enc->hdr_len = mpp_packet_get_length(enc->hdr_pkt); + enc->hdr_ready = 1; + hal_task->header_length = enc->hdr_len; enc_dbg_detail("task %d update header length %d\n", - frm->seq_idx, mpp_packet_get_length(packet)); + frm->seq_idx, hal_task->header_length); + + mpp_packet_copy(packet, enc->hdr_pkt); + task.status.enc_add_header = 1; } + // 13. setup input frame and output packet hal_task->frame = frame; hal_task->input = mpp_frame_get_buffer(frame); hal_task->packet = packet; @@ -634,22 +660,38 @@ void *mpp_enc_thread(void *data) hal_task->length = mpp_packet_get_length(packet); mpp_task_meta_get_buffer(task_in, KEY_MOTION_INFO, &hal_task->mv_info); - // 13. backup dpb + // 14. backup dpb enc_dbg_detail("task %d enc start\n", frm->seq_idx); + task.status.enc_backup = 1; RUN_ENC_IMPL_FUNC(enc_impl_start, impl, hal_task, mpp, ret); TASK_REENCODE: - // 14. restore and process dpb - if (!frm->reencode || frm->re_dpb_proc) { - enc_dbg_detail("task %d enc proc dpb\n", frm->seq_idx); - RUN_ENC_IMPL_FUNC(enc_impl_proc_dpb, impl, hal_task, mpp, ret); - } - + // 15. restore and process dpb if (!frm->reencode) { + if (!frm->re_dpb_proc) { + enc_dbg_detail("task %d enc proc dpb\n", frm->seq_idx); + RUN_ENC_IMPL_FUNC(enc_impl_proc_dpb, impl, hal_task, mpp, ret); + } + enc_dbg_detail("task %d rc frame start\n", frm->seq_idx); RUN_ENC_RC_FUNC(rc_frm_start, enc->rc_ctx, rc_task, mpp, ret); + task.status.enc_proc_dpb = 1; if (frm->re_dpb_proc) goto TASK_REENCODE; + + // 16. generate header before hardware stream + if (enc->hdr_mode == MPP_ENC_HEADER_MODE_EACH_IDR && + frm->is_intra && !task.status.enc_add_header) { + + enc_dbg_detail("task %d IDR header length %d\n", + frm->seq_idx, enc->hdr_len); + + mpp_packet_copy(packet, enc->hdr_pkt); + task.status.enc_add_header = 1; + + hal_task->header_length = enc->hdr_len; + hal_task->length += enc->hdr_len; + } } frm->reencode = 0; @@ -683,7 +725,7 @@ void *mpp_enc_thread(void *data) enc_dbg_detail("task %d rc frame end\n", frm->seq_idx); RUN_ENC_RC_FUNC(rc_frm_end, enc->rc_ctx, rc_task, mpp, ret); if (frm->reencode) { - mpp_log_f("reencode time %d\n", frm->reencode_times); + enc_dbg_reenc("reencode time %d\n", frm->reencode_times); goto TASK_REENCODE; } @@ -802,6 +844,13 @@ MPP_RET mpp_enc_init_v2(MppEnc *enc, MppEncCfg *cfg) p->enc_hal = enc_hal; p->mpp = cfg->mpp; + { // create header packet storage + size_t size = SZ_1K; + void *ptr = mpp_calloc_size(void, size); + + mpp_packet_init(&p->hdr_pkt, ptr, size); + } + /* NOTE: setup configure coding for check */ p->cfg.codec.coding = coding; p->set.codec.coding = coding; @@ -944,8 +993,8 @@ MPP_RET mpp_enc_control_v2(MppEnc ctx, MpiCmd cmd, void *param) return MPP_ERR_NULL_PTR; } - MPP_RET ret = MPP_OK; AutoMutex auto_lock(&enc->lock); + MPP_RET ret = MPP_OK; enc_dbg_ctrl("sending cmd %d param %p\n", cmd, param); @@ -962,10 +1011,15 @@ MPP_RET mpp_enc_control_v2(MppEnc ctx, MpiCmd cmd, void *param) enc_dbg_ctrl("get rc config\n"); memcpy(param, &enc->cfg.rc, sizeof(enc->cfg.rc)); } break; + case MPP_ENC_GET_HEADER_MODE : { + enc_dbg_ctrl("get header mode\n"); + memcpy(param, &enc->hdr_mode, sizeof(enc->hdr_mode)); + } break; default : { // Cmd which is not get configure will handle by enc_impl - enc->cmd = cmd; - enc->param = param; + enc->cmd = cmd; + enc->param = param; + enc->cmd_ret = &ret; enc->cmd_send++; mpp_enc_notify_v2(ctx, MPP_ENC_CONTROL); diff --git a/mpp/hal/inc/hal_enc_task.h b/mpp/hal/inc/hal_enc_task.h index 123eb096..6d250b8d 100644 --- a/mpp/hal/inc/hal_enc_task.h +++ b/mpp/hal/inc/hal_enc_task.h @@ -45,6 +45,9 @@ typedef struct HalEncTask_t { // current tesk output stream buffer MppPacket packet; MppBuffer output; + RK_U32 header_length; + RK_U32 sei_length; + RK_U32 hw_length; RK_U32 length; // current tesk input slot buffer