[encoder]: Change rate control work flow

1. Add mpp_rc_api and mpp_rc_defs for open rc module to external users.
2. Add RcImplApi registration and setup function.
3. Separate RC module from the encoder implement.
4. Use EncFrmStatus and EncRcTaskInfo to control work flow.
5. proc_rc and update_rc function in enc_impl are removed.
6. Use rc_frm_start and rc_hal_start to process rate control.
7. Add more RcCfg setup in mpp_enc_v2.cpp.
8. Use rc_task to replace all the frame status and rc config transmit.
   EncFrmStatus is for encoder flow control.
   EncRcTaskInfo is for communication between rc / hal / hardware

Change-Id: Ia72b0e0804bfca13963c2b2a5887983fd9b5bcbf
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Signed-off-by: sayon.chen <sayon.chen@rock-chips.com>
This commit is contained in:
Herman Chen 2020-03-12 16:49:18 +08:00
parent 74d050c4df
commit 6d52e80b27
31 changed files with 1202 additions and 784 deletions

View file

@ -14,10 +14,11 @@
* limitations under the License.
*/
#ifndef __RC_API_H__
#define __RC_API_H__
#ifndef __MPP_RC_API_H__
#define __MPP_RC_API_H__
#include "mpp_enc_cfg.h"
#include "mpp_err.h"
#include "mpp_rc_defs.h"
/*
* Mpp rate control has three parts:
@ -92,6 +93,10 @@ typedef struct RcFpsCfg_t {
* It will be updated on rc/prep/gopref config changed.
*/
typedef struct RcCfg_s {
/* encode image size */
RK_S32 width;
RK_S32 height;
/* Use rc_mode to find different api */
RcMode mode;
@ -115,6 +120,7 @@ typedef struct RcCfg_s {
RK_S32 layer_bit_prop[4];
/* quality parameter */
RK_S32 init_quality;
RK_S32 max_quality;
RK_S32 min_quality;
RK_S32 max_i_quality;
@ -141,38 +147,7 @@ typedef struct RcCfg_s {
} RcCfg;
/*
* Bit and quality of each frame for each frame encoding
*
* Quality is not equal to qp.
* Different codec and hardware will translate it to different meaning.
*/
typedef struct RcHalCfg_s {
RK_S32 seq_idx;
RK_S32 bit_target;
RK_S32 bit_max;
RK_S32 bit_min;
RK_S32 bit_real;
RK_S32 quality_target;
RK_S32 quality_max;
RK_S32 quality_min;
RK_S32 quality_real; /*scale 64 */
RK_S32 inter_lv8_prop; /*scale 256 */
RK_S32 intra_lv4_prop; /*scale 256 */
RK_S32 sse;
RK_S32 madi;
RK_S32 madp; /*scale 256 */
RK_S32 next_i_ratio;
RK_S32 next_ratio;
RK_S32 need_reenc;
} RcHalCfg;
/*
* Different rate control strategy like CBR/VBR/AVBR/QVBR/CVBR will be
* implemented by different api structure
* Different rate control strategy will be implemented by different API config
*/
typedef struct RcImplApi_t {
char *name;
@ -182,14 +157,64 @@ typedef struct RcImplApi_t {
MPP_RET (*init)(void *ctx, RcCfg *cfg);
MPP_RET (*deinit)(void *ctx);
MPP_RET (*check_drop)(void *ctx, EncRcTask *task);
/*
* start - frame level rate control start.
* The RcHalCfg will be output to hal for hardware to implement.
* end - frame level rate control end
* The RcHalCfg is returned for real quality and bitrate.
* frm_start - frame level rate control frm_start.
* The EncRcTaskInfo will be output to hal for hardware to implement.
* frm_end - frame level rate control frm_end.
* The EncRcTaskInfo is returned for real quality and bitrate.
*/
MPP_RET (*start)(void *ctx, RcHalCfg *cfg, EncFrmStatus *frm);
MPP_RET (*end)(void *ctx, RcHalCfg *cfg);
MPP_RET (*frm_start)(void *ctx, EncRcTask *task);
MPP_RET (*frm_end)(void *ctx, EncRcTask *task);
/*
* hal_start - hardware level rate control start.
* The EncRcTaskInfo will be output to hal for hardware to implement.
* hal_end - hardware level rate control end.
* The EncRcTaskInfo is returned for real quality and bitrate.
*/
MPP_RET (*hal_start)(void *ctx, EncRcTask *task);
MPP_RET (*hal_end)(void *ctx, EncRcTask *task);
} RcImplApi;
#endif /* __RC_API_H__ */
/*
* structures for RC API register and query
*/
typedef struct RcApiBrief_t {
const char *name;
MppCodingType type;
} RcApiBrief;
typedef struct RcApiQueryAll_t {
/* input param for query */
RcApiBrief *brief;
RK_S32 max_count;
/* output query count */
RK_S32 count;
} RcApiQueryAll;
typedef struct RcApiQueryType_t {
/* input param for query */
RcApiBrief *brief;
RK_S32 max_count;
MppCodingType type;
/* output query count */
RK_S32 count;
} RcApiQueryType;
#ifdef __cplusplus
extern "C" {
#endif
MPP_RET rc_api_add(const RcImplApi *api);
MPP_RET rc_brief_get_all(RcApiQueryAll *query);
MPP_RET rc_brief_get_by_type(RcApiQueryType *query);
#ifdef __cplusplus
}
#endif
#endif /* __MPP_RC_API_H__ */

143
inc/mpp_rc_defs.h Normal file
View file

@ -0,0 +1,143 @@
/*
* Copyright 2016 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __RC_DEFS_H__
#define __RC_DEFS_H__
#include "rk_type.h"
/*
* EncFrmStatus controls record the encoding frame status and also control
* work flow of encoder. It is the communicat channel between encoder implement
* module, rate control module and hardware module.
*
* bit 0 ~ 31 frame status
* 0 ~ 15 current frame status
* 16 ~ 31 reference frame status
* bit 32 ~ 63 encoding flow control
*/
typedef struct EncFrmStatus_t {
/*
* bit 0 ~ 31 frame status
*/
/*
* 0 - inter frame
* 1 - intra frame
*/
RK_U32 is_intra : 1;
/*
* Valid when is_intra is true
* 0 - normal intra frame
* 1 - IDR frame
*/
RK_U32 is_idr : 1;
/*
* 0 - mark as reference frame
* 1 - mark as non-refernce frame
*/
RK_U32 is_non_ref : 1;
/*
* Valid when is_non_ref is false
* 0 - mark as short-term reference frame
* 1 - mark as long-term refernce frame
*/
RK_U32 is_lt_ref : 1;
RK_U32 reserved0 : 4;
/* bit 8 - 15 */
RK_U32 lt_idx : 4;
RK_U32 temporal_id : 4;
/* distance between current frame and reference frame */
RK_S32 ref_dist : 16;
/*
* bit 32 ~ 63 encoder flow control flags
*/
/*
* 0 - normal frame encoding
* 1 - current frame will be dropped
*/
RK_U32 drop : 1;
/*
* 0 - rate control module does not change frame type parameter
* 1 - rate control module changes frame type parameter reencode is needed
* to reprocess the dpb process. Also this means dpb module will follow
* the frame status parameter provided by rate control module.
*/
RK_U32 re_dpb_proc : 1;
/*
* 0 - current frame encoding is in normal flow
* 1 - current frame encoding is in reencode flow
*/
RK_U32 reencode : 1;
/*
* When true current frame size is super large then the frame should be reencoded.
*/
RK_U32 super_frame : 1;
/*
* When true currnet frame is force to encoded as software skip frame
*/
RK_U32 force_pskip : 1;
RK_U32 reserved1 : 3;
/* reencode times */
RK_U32 reencode_times : 8;
/* sequential index for each frame */
RK_U32 seq_idx : 16;
} EncFrmStatus;
/*
* communication channel between rc / hal / hardware
*
* rc -> hal bit_target / bit_max / bit_min
* hal -> hw quality_target / quality_max / quality_min
* hw -> rc / hal bit_real / quality_real / madi / madp
*/
typedef struct EncRcCommonInfo_t {
/* rc to hal */
RK_S32 bit_target;
RK_S32 bit_max;
RK_S32 bit_min;
RK_S32 quality_target;
RK_S32 quality_max;
RK_S32 quality_min;
/* rc from hardware */
RK_S32 bit_real;
RK_S32 quality_real;
RK_S32 madi;
RK_S32 madp;
RK_S32 reserve[16];
} EncRcTaskInfo;
typedef struct EncRcTask_s {
EncFrmStatus frm;
EncRcTaskInfo info;
} EncRcTask;
#endif /* __RC_DEFS_H__ */

View file

@ -268,10 +268,8 @@ const EncImplApi api_h264e_controller = {
NULL,
NULL,
NULL,
NULL,
h264e_encode,
NULL,
NULL,
h264e_reset,
h264e_flush,
h264e_callback,

View file

@ -73,9 +73,6 @@ typedef struct {
/* output to hal */
RK_S32 syn_num;
H264eSyntaxDesc syntax[H264E_SYN_BUTT];
/* input from hal */
RcHalCfg hal_rc_cfg;
} H264eCtx;
static void init_h264e_cfg_set(MppEncCfgSet *cfg)
@ -182,11 +179,6 @@ static MPP_RET h264e_deinit(void *ctx)
h264e_dbg_func("enter\n");
if (p->rc_ctx) {
rc_deinit(p->rc_ctx);
p->rc_ctx = NULL;
}
if (p->hdr_pkt)
mpp_packet_deinit(&p->hdr_pkt);
@ -447,10 +439,7 @@ static MPP_RET h264e_gen_hdr(void *ctx, MppPacket pkt)
p->hdr_len = mpp_packet_get_length(p->hdr_pkt);
if (pkt) {
void *dst = mpp_packet_get_data(pkt);
void *src = p->hdr_buf;
memcpy(dst, src, p->hdr_len);
mpp_packet_write(pkt, 0, p->hdr_buf, p->hdr_len);
mpp_packet_set_length(pkt, p->hdr_len);
}
@ -458,103 +447,17 @@ static MPP_RET h264e_gen_hdr(void *ctx, MppPacket pkt)
return MPP_OK;
}
static void set_rc_cfg(RcCfg *cfg, MppEncRcCfg *rc, MppEncGopRef *ref)
{
switch (rc->rc_mode) {
case MPP_ENC_RC_MODE_CBR : {
cfg->mode = RC_CBR;
} break;
case MPP_ENC_RC_MODE_VBR : {
cfg->mode = RC_VBR;
} break;
default : {
cfg->mode = RC_AVBR;
} break;
}
cfg->fps.fps_in_flex = rc->fps_in_flex;
cfg->fps.fps_in_num = rc->fps_in_num;
cfg->fps.fps_in_denorm = rc->fps_in_denorm;
cfg->fps.fps_out_flex = rc->fps_out_flex;
cfg->fps.fps_out_num = rc->fps_out_num;
cfg->fps.fps_out_denorm = rc->fps_out_denorm;
cfg->igop = rc->gop;
mpp_log_f("fps_in_flex %d\n", cfg->fps.fps_in_flex);
mpp_log_f("fps_in_num %d\n", cfg->fps.fps_in_num);
mpp_log_f("fps_in_denorm %d\n", cfg->fps.fps_in_denorm);
mpp_log_f("fps_out_flex %d\n", cfg->fps.fps_out_flex);
mpp_log_f("fps_out_num %d\n", cfg->fps.fps_out_num);
mpp_log_f("fps_out_denorm %d\n", cfg->fps.fps_out_denorm);
cfg->bps_target = rc->bps_target;
cfg->bps_max = rc->bps_max;
cfg->bps_min = rc->bps_min;
cfg->stat_times = 1;
if (ref->gop_cfg_enable)
cfg->vgop = ref->ref_gop_len;
else
cfg->vgop = 0;
if (ref->layer_rc_enable) {
RK_S32 i;
for (i = 0; i < MAX_TEMPORAL_LAYER; i++) {
cfg->layer_bit_prop[i] = ref->layer_weight[i];
}
} else {
cfg->layer_bit_prop[0] = 256;
cfg->layer_bit_prop[1] = 0;
cfg->layer_bit_prop[2] = 0;
cfg->layer_bit_prop[3] = 0;
}
cfg->max_reencode_times = 1;
}
static MPP_RET h264e_start(void *ctx, HalEncTask *task)
{
H264eCtx *p = (H264eCtx *)ctx;
MppEncCfgSet *cfg = p->cfg;
MppEncGopRef *ref = &cfg->gop_ref;
MppEncRcCfg *rc = &cfg->rc;
h264e_dbg_func("enter\n");
/* Step 1: Check and update config */
if (rc->change || ref->change) {
if (p->rc_ctx) {
rc_deinit(p->rc_ctx);
p->rc_ctx = NULL;
}
RcCfg rc_cfg;
set_rc_cfg(&rc_cfg, rc, ref);
rc_init(&p->rc_ctx, MPP_VIDEO_CodingAVC, NULL);
mpp_assert(p->rc_ctx);
rc_update_usr_cfg(p->rc_ctx, &rc_cfg);
}
/*
* Step 2: Fps conversion
*
* Determine current frame which should be encoded or not according to
* input and output frame rate.
*/
task->valid = !rc_frm_check_drop(p->rc_ctx);
if (!task->valid)
mpp_log_f("drop one frame by fps\n");
/*
* Step 3: Backup dpb for reencode
*/
/* Backup dpb for reencode */
h264e_dpb_copy(&p->dpb_bak, &p->dpb);
h264e_dbg_func("leave\n");
(void) task;
return MPP_OK;
}
@ -565,6 +468,7 @@ static MPP_RET h264e_proc_dpb(void *ctx, HalEncTask *task)
H264eDpb *dpb = &p->dpb;
H264eFrmInfo *frms = &p->frms;
H264eDpbFrmCfg frm_cfg;
EncFrmStatus *frm = &task->rc_task->frm;
MppFrame frame = task->frame;
MppMeta meta = mpp_frame_get_meta(frame);
RK_S32 i;
@ -597,7 +501,11 @@ static MPP_RET h264e_proc_dpb(void *ctx, HalEncTask *task)
frms->seq_idx = dpb->curr->seq_idx;
frms->curr_idx = dpb->curr->slot_idx;
frms->refr_idx = (dpb->refr) ? dpb->refr->slot_idx : frms->curr_idx;
frms->status = dpb->curr->status;
// update frame status for rc module
*frm = dpb->curr->status;
frm->seq_idx = dpb->curr->seq_idx;
for (i = 0; i < (RK_S32)MPP_ARRAY_ELEMS(frms->usage); i++)
frms->usage[i] = dpb->frames[i].on_used;
@ -621,27 +529,6 @@ static MPP_RET h264e_proc_dpb(void *ctx, HalEncTask *task)
return MPP_OK;
}
static MPP_RET h264e_proc_rc(void *ctx, HalEncTask *task)
{
H264eCtx *p = (H264eCtx *)ctx;
H264eFrmInfo *frms = &p->frms;
MppEncCfgSet *cfg = p->cfg;
MppEncGopRef *ref = &cfg->gop_ref;
MppEncRcCfg *rc = &cfg->rc;
h264e_dbg_func("enter\n");
rc_frm_start(p->rc_ctx, &frms->rc_cfg, &frms->status);
rc->change = 0;
ref->change = 0;
(void)task;
h264e_dbg_func("leave\n");
return MPP_OK;
}
static MPP_RET h264e_proc_hal(void *ctx, HalEncTask *task)
{
H264eCtx *p = (H264eCtx *)ctx;
@ -668,50 +555,16 @@ static MPP_RET h264e_proc_hal(void *ctx, HalEncTask *task)
static MPP_RET h264e_update_hal(void *ctx, HalEncTask *task)
{
H264eCtx *p = (H264eCtx *)ctx;
RcHalCfg *rc_hal_cfg = task->hal_ret.data;
(void) ctx;
(void) task;
h264e_dbg_func("enter\n");
p->hal_rc_cfg = *rc_hal_cfg;
h264e_dbg_func("leave\n");
return MPP_OK;
}
static MPP_RET h264e_update_rc(void *ctx, HalEncTask *task)
{
H264eCtx *p = (H264eCtx *)ctx;
h264e_dbg_func("enter\n");
rc_frm_end(p->rc_ctx, &p->hal_rc_cfg);
(void)task;
h264e_dbg_func("leave\n");
return MPP_OK;
}
static MPP_RET h264e_reset(void *ctx)
{
(void)ctx;
h264e_dbg_func("enter\n");
h264e_dbg_func("leave\n");
return MPP_OK;
}
static MPP_RET h264e_flush(void *ctx)
{
(void)ctx;
h264e_dbg_func("enter\n");
h264e_dbg_func("leave\n");
return MPP_OK;
}
/*!
***********************************************************************
* \brief
@ -729,11 +582,9 @@ const EncImplApi api_h264e = {
h264e_gen_hdr,
h264e_start,
h264e_proc_dpb,
h264e_proc_rc,
h264e_proc_hal,
h264e_update_hal,
h264e_update_rc,
h264e_reset,
h264e_flush,
NULL,
NULL,
NULL,
};

View file

@ -208,10 +208,8 @@ const EncImplApi api_h265e_controller = {
NULL,
NULL,
NULL,
NULL,
h265e_encode,
NULL,
NULL,
h265e_reset,
h265e_flush,
h265e_callback,

View file

@ -168,9 +168,6 @@ static MPP_RET h265e_deinit(void *ctx)
return MPP_ERR_NULL_PTR;
}
if (p->rc_ctx)
rc_deinit(p->rc_ctx);
h265e_deinit_extra_info(p->extra_info);
MPP_FREE(p->extra_info);
@ -199,90 +196,16 @@ static MPP_RET h265e_gen_hdr(void *ctx, MppPacket pkt)
return MPP_OK;
}
static void h265_set_rc_cfg(RcCfg *cfg, MppEncRcCfg *rc, MppEncGopRef *ref)
{
switch (rc->rc_mode) {
case MPP_ENC_RC_MODE_CBR : {
cfg->mode = RC_CBR;
} break;
case MPP_ENC_RC_MODE_VBR : {
cfg->mode = RC_VBR;
} break;
case MPP_ENC_RC_MODE_FIXQP: {
cfg->mode = RC_FIXQP;
} break;
default : {
cfg->mode = RC_AVBR;
} break;
}
cfg->fps.fps_in_flex = rc->fps_in_flex;
cfg->fps.fps_in_num = rc->fps_in_num;
cfg->fps.fps_in_denorm = rc->fps_in_denorm;
cfg->fps.fps_out_flex = rc->fps_out_flex;
cfg->fps.fps_out_num = rc->fps_out_num;
cfg->fps.fps_out_denorm = rc->fps_out_denorm;
cfg->igop = rc->gop;
cfg->max_i_bit_prop = 20;
cfg->bps_target = rc->bps_target;
cfg->bps_max = rc->bps_max;
cfg->bps_min = rc->bps_min;
cfg->vgop = (ref->gop_cfg_enable) ? ref->ref_gop_len : 0;
if (ref->layer_rc_enable) {
RK_S32 i;
for (i = 0; i < MAX_TEMPORAL_LAYER; i++) {
cfg->layer_bit_prop[i] = ref->layer_weight[i];
}
} else {
cfg->layer_bit_prop[0] = 256;
cfg->layer_bit_prop[1] = 0;
cfg->layer_bit_prop[2] = 0;
cfg->layer_bit_prop[3] = 0;
}
cfg->stat_times = rc->stat_times;
cfg->max_reencode_times = 1;
}
static MPP_RET h265e_start(void *ctx, HalEncTask *task)
{
H265eCtx *p = (H265eCtx *)ctx;
MppEncCfgSet *cfg = p->cfg;
MppEncGopRef *ref = &cfg->gop_ref;
MppEncRcCfg *rc = &cfg->rc;
MppEncCodecCfg *codec = &p->cfg->codec;
h265e_dbg_func("enter\n");
/* Step 1: Check and update config */
if (rc->change || ref->change) {
if (p->rc_ctx) {
rc_deinit(p->rc_ctx);
p->rc_ctx = NULL;
}
RcCfg rc_cfg;
h265_set_rc_cfg(&rc_cfg, rc, ref);
rc_init(&p->rc_ctx, MPP_VIDEO_CodingHEVC, NULL);
mpp_assert(p->rc_ctx);
rc_update_usr_cfg(p->rc_ctx, &rc_cfg);
p->rc_ready = 1;
rc->change = 0;
ref->change = 0;
}
if (codec->change) {
if (NULL == p->dpb) {
h265e_dpb_init(&p->dpb, &p->dpbcfg);
}
if (rc->gop < 0) {
p->dpb->idr_gap = 10000;
@ -299,8 +222,6 @@ static MPP_RET h265e_start(void *ctx, HalEncTask *task)
* input and output frame rate.
*/
if (p->rc_ctx)
task->valid = !rc_frm_check_drop(p->rc_ctx);
if (!task->valid)
mpp_log_f("drop one frame\n");
@ -320,6 +241,7 @@ static MPP_RET h265e_proc_dpb(void *ctx, HalEncTask *task)
MppFrame frame = task->frame;
H265eDpbCfg *dpb_cfg = &p->dpbcfg;
H265eFrmInfo *frms = &p->frms;
EncRcTask *rc_task = task->rc_task;
MppMeta meta = mpp_frame_get_meta(frame);
RK_S32 mb_wd64, mb_h64;
@ -329,10 +251,7 @@ static MPP_RET h265e_proc_dpb(void *ctx, HalEncTask *task)
mb_h64 = (p->cfg->prep.height + 63) / 64;
if (NULL == p->dpb) {
h265e_dpb_init(&p->dpb, &p->dpbcfg);
}
if (p->idr_request) {
@ -354,8 +273,8 @@ static MPP_RET h265e_proc_dpb(void *ctx, HalEncTask *task)
h265e_slice_init(ctx, p->slice);
h265e_dpb_build_list(p->dpb);
frms->seq_idx = p->dpb->curr->seq_idx;
frms->status = p->dpb->curr->status;
p->dpb->curr->status.seq_idx = p->dpb->curr->seq_idx;
rc_task->frm = p->dpb->curr->status;
frms->mb_per_frame = mb_wd64 * mb_h64;
frms->mb_raw = mb_h64;
@ -365,28 +284,6 @@ static MPP_RET h265e_proc_dpb(void *ctx, HalEncTask *task)
return MPP_OK;
}
static MPP_RET h265e_proc_rc(void *ctx, HalEncTask *task)
{
(void)task;
H265eCtx *p = (H265eCtx *)ctx;
H265eFrmInfo *frms = &p->frms;
MppEncRcCfg *rc = &p->cfg->rc;
h265e_dbg_func("enter\n");
if (!p->rc_ready && rc->rc_mode != MPP_ENC_RC_MODE_FIXQP) {
mpp_err_f("not initialize encoding\n");
return MPP_NOK;
}
if (rc->rc_mode != MPP_ENC_RC_MODE_FIXQP) {
rc_frm_start(p->rc_ctx, &frms->rc_cfg, &frms->status);
}
p->frms.status.reencode = 0;
h265e_dbg_func("leave\n");
return MPP_OK;
}
static MPP_RET h265e_proc_hal(void *ctx, HalEncTask *task)
{
H265eCtx *p = (H265eCtx *)ctx;
@ -402,10 +299,6 @@ static MPP_RET h265e_proc_hal(void *ctx, HalEncTask *task)
h265e_syntax_fill(ctx);
task->valid = 1;
task->syntax.data = syntax;
task->hal_ret.data = &p->frms.rc_cfg;
task->hal_ret.number = 1;
h265e_dbg_func("leave ctx %p \n", ctx);
return MPP_OK;
}
@ -432,25 +325,6 @@ static MPP_RET h265e_update_hal(void *ctx, HalEncTask *task)
return MPP_OK;
}
static MPP_RET h265e_update_rc(void *ctx, HalEncTask *task)
{
H265eCtx *p = (H265eCtx *)ctx;
MppEncRcCfg *rc = &p->cfg->rc;
RcHalCfg *rc_hal_cfg = NULL;
h265e_dbg_func("enter\n");
rc_hal_cfg = (RcHalCfg *)task->hal_ret.data;
if (rc->rc_mode != MPP_ENC_RC_MODE_FIXQP) {
rc_frm_end(p->rc_ctx, rc_hal_cfg);
if (rc_hal_cfg->need_reenc) {
p->frms.status.reencode = 1;
}
}
h265e_dbg_func("leave\n");
return MPP_OK;
}
static MPP_RET h265e_reset(void *ctx)
{
if (ctx == NULL) {
@ -651,10 +525,8 @@ const EncImplApi api_h265e = {
h265e_gen_hdr,
h265e_start,
h265e_proc_dpb,
h265e_proc_rc,
h265e_proc_hal,
h265e_update_hal,
h265e_update_rc,
h265e_reset,
h265e_flush,
NULL,

View file

@ -25,7 +25,6 @@
#include "h265e_syntax_new.h"
#include "h265e_dpb.h"
#include "enc_impl_api.h"
#include "rc_api.h"
#define H265E_DBG_FUNCTION (0x00000001)
#define H265E_DBG_INPUT (0x00000010)
@ -60,7 +59,6 @@ typedef struct H265eCtx_t {
MppEncCfgSet *set;
MppDeviceId dev_id;
MppRateControl *rc;
RcCtx rc_ctx;
RK_U32 rc_ready;
RK_S32 idr_request;

View file

@ -132,10 +132,8 @@ const EncImplApi api_jpege_controller = {
.gen_hdr = NULL,
.start = NULL,
.proc_dpb = NULL,
.proc_rc = NULL,
.proc_hal = jpege_encode,
.update_hal = NULL,
.update_rc = NULL,
.reset = jpege_reset,
.flush = jpege_flush,
.callback = jpege_callback,

View file

@ -229,10 +229,8 @@ const EncImplApi api_vp8e_controller = {
NULL,
NULL,
NULL,
NULL,
vp8e_encode,
NULL,
NULL,
vp8e_reset,
vp8e_flush,
vp8e_callback,

View file

@ -67,11 +67,9 @@ typedef struct EncImplApi_t {
MPP_RET (*start)(void *ctx, HalEncTask *task);
MPP_RET (*proc_dpb)(void *ctx, HalEncTask *task);
MPP_RET (*proc_rc)(void *ctx, HalEncTask *task);
MPP_RET (*proc_hal)(void *ctx, HalEncTask *task);
MPP_RET (*update_hal)(void *ctx, HalEncTask *task);
MPP_RET (*update_rc)(void *ctx, HalEncTask *task);
MPP_RET (*reset)(void *ctx);
MPP_RET (*flush)(void *ctx);

View file

@ -33,11 +33,9 @@ MPP_RET enc_impl_gen_hdr(EncImpl ctrl, MppPacket pkt);
MPP_RET enc_impl_start(EncImpl ctrl, HalEncTask *task);
MPP_RET enc_impl_proc_dpb(EncImpl ctrl, HalEncTask *task);
MPP_RET enc_impl_proc_rc(EncImpl ctrl, HalEncTask *task);
MPP_RET enc_impl_proc_hal(EncImpl ctrl, HalEncTask *task);
MPP_RET enc_impl_update_hal(EncImpl ctrl, HalEncTask *task);
MPP_RET enc_impl_update_rc(EncImpl ctrl, HalEncTask *task);
MPP_RET hal_enc_callback(void* ctrl, void *err_info);

View file

@ -19,7 +19,7 @@
#include "mpp_err.h"
#include "rc_api.h"
#include "mpp_rc_api.h"
/*
* Mpp rate control principle
@ -62,8 +62,6 @@ typedef void* RcCtx;
extern "C" {
#endif
MPP_RET rc_api_register(const RcImplApi *api);
MPP_RET rc_init(RcCtx *ctx, MppCodingType type, const char *name);
MPP_RET rc_deinit(RcCtx ctx);
@ -71,17 +69,14 @@ MPP_RET rc_deinit(RcCtx ctx);
MPP_RET rc_update_usr_cfg(RcCtx ctx, RcCfg *cfg);
/* Frame rate convertion */
RK_S32 rc_frm_check_drop(RcCtx ctx);
/* Frame type decision */
RK_S32 rc_frm_check_type(RcCtx ctx);
MPP_RET rc_frm_check_drop(RcCtx ctx, EncRcTask *task);
/* Frame level rate and quality control */
MPP_RET rc_frm_start(RcCtx ctx, RcHalCfg *cfg, EncFrmStatus *frm);
MPP_RET rc_frm_end(RcCtx ctx, RcHalCfg *cfg);
MPP_RET rc_frm_start(RcCtx ctx, EncRcTask *task);
MPP_RET rc_frm_end(RcCtx ctx, EncRcTask *task);
MPP_RET rc_hal_start(RcCtx ctx, RcHalCfg *cfg, EncFrmStatus *frm);
MPP_RET rc_hal_end(RcCtx ctx, RcHalCfg *cfg, EncFrmStatus *frm);
MPP_RET rc_hal_start(RcCtx ctx, EncRcTask *task);
MPP_RET rc_hal_end(RcCtx ctx, EncRcTask *task);
#ifdef __cplusplus
}

View file

@ -17,6 +17,7 @@
#ifndef __RC_DATA_H__
#define __RC_DATA_H__
#include "mpp_rc_defs.h"
#include "rc_hal.h"
typedef enum RcDataIndexType_e {
@ -29,49 +30,6 @@ typedef enum RcDataIndexType_e {
#define RC_FRM_TYPE_I 0
#define RC_FRM_TYPE_P 1
typedef struct EncFrmStatus_t {
/*
* 0 - inter frame
* 1 - intra frame
*/
RK_U32 is_intra : 1;
/*
* Valid when is_intra is true
* 0 - normal intra frame
* 1 - IDR frame
*/
RK_U32 is_idr : 1;
/*
* 0 - mark as reference frame
* 1 - mark as non-refernce frame
*/
RK_U32 is_non_ref : 1;
/*
* Valid when is_non_ref is false
* 0 - mark as short-term reference frame
* 1 - mark as long-term refernce frame
*/
RK_U32 is_lt_ref : 1;
RK_U32 lt_idx : 4;
RK_U32 temporal_id : 4;
/*
* distance between current frame and reference frame
*/
RK_S32 ref_dist : 16;
/*
* reencode flag and force pskip flag
*/
RK_U32 reencode : 1;
RK_U32 force_pskip : 1;
RK_U32 stuff : 2;
} EncFrmStatus;
/*
* base_cnt - rate control base data storage number
* extra_cnt - rate control extra data storage number

View file

@ -190,21 +190,6 @@ MPP_RET enc_impl_proc_dpb(EncImpl impl, HalEncTask *task)
return ret;
}
MPP_RET enc_impl_proc_rc(EncImpl impl, HalEncTask *task)
{
if (NULL == impl) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
MPP_RET ret = MPP_OK;
EncImplCtx *p = (EncImplCtx *)impl;
if (p->api->proc_rc)
ret = p->api->proc_rc(p->ctx, task);
return ret;
}
MPP_RET enc_impl_proc_hal(EncImpl impl, HalEncTask *task)
{
if (NULL == impl || NULL == task) {
@ -235,21 +220,6 @@ MPP_RET enc_impl_update_hal(EncImpl impl, HalEncTask *task)
return ret;
}
MPP_RET enc_impl_update_rc(EncImpl impl, HalEncTask *task)
{
if (NULL == impl) {
mpp_err_f("found NULL input\n");
return MPP_ERR_NULL_PTR;
}
MPP_RET ret = MPP_OK;
EncImplCtx *p = (EncImplCtx *)impl;
if (p->api->update_rc)
ret = p->api->update_rc(p->ctx, task);
return ret;
}
MPP_RET hal_enc_callback(void *impl, void *err_info)
{
if (NULL == impl) {

View file

@ -31,13 +31,32 @@
#include "mpp_enc_hal.h"
#include "hal_h264e_api_v2.h"
#include "rc.h"
RK_U32 mpp_enc_debug = 0;
typedef struct RcApiStatus_t {
RK_U32 rc_api_inited : 1;
RK_U32 rc_api_user_cfg : 1;
RK_U32 rc_api_updated : 1;
RK_U32 rc_cfg_updated : 1;
} RcApiStatus;
typedef struct MppEncImpl_t {
MppCodingType coding;
EncImpl impl;
MppEncHal enc_hal;
/*
* Rate control plugin parameters
*/
RcApiStatus rc_status;
RK_S32 rc_api_updated;
RK_S32 rc_cfg_updated;
RcApiBrief rc_brief;
RcCtx rc_ctx;
EncRcTask rc_task;
MppThread *thread_enc;
void *mpp;
@ -93,17 +112,38 @@ typedef union EncTaskWait_u {
};
} EncTaskWait;
/* encoder internal work flow */
typedef union EncTaskStatus_u {
RK_U32 val;
struct {
RK_U32 task_in_rdy : 1;
RK_U32 task_out_rdy : 1;
RK_U32 task_in_rdy : 1;
RK_U32 task_out_rdy : 1;
RK_U32 rc_check_frm_drop : 1; // rc stage
RK_U32 enc_backup : 1; // enc stage
RK_U32 enc_restore : 1; // reenc flow start point
RK_U32 enc_proc_dpb : 1; // enc stage
RK_U32 rc_frm_start : 1; // rc stage
RK_U32 check_type_reenc : 1; // flow checkpoint if reenc -> enc_restore
RK_U32 enc_proc_hal : 1; // enc stage
RK_U32 hal_get_task : 1; // hal stage
RK_U32 rc_hal_start : 1; // rc stage
RK_U32 hal_gen_reg : 1; // hal stage
RK_U32 hal_start : 1; // hal stage
RK_U32 hal_wait : 1; // hal stage NOTE: special in low delay mode
RK_U32 rc_hal_end : 1; // rc stage
RK_U32 hal_ret_task : 1; // hal stage
RK_U32 enc_update_hal : 1; // enc stage
RK_U32 rc_frm_end : 1; // rc stage
RK_U32 check_rc_reenc : 1; // flow checkpoint if reenc -> enc_restore
};
} EncTaskStatus;
typedef struct EncTask_t {
RK_S32 seq_idx;
EncTaskStatus status;
EncTaskWait wait;
EncFrmStatus frm;
HalTaskInfo info;
} EncTask;
@ -112,6 +152,11 @@ static void reset_hal_enc_task(HalEncTask *task)
memset(task, 0, sizeof(*task));
}
static void reset_enc_rc_task(EncRcTask *task)
{
memset(task, 0, sizeof(*task));
}
static MPP_RET release_task_in_port(MppPort port)
{
MPP_RET ret = MPP_OK;
@ -217,6 +262,34 @@ static void mpp_enc_proc_cfg(MppEncImpl *enc)
enc->hdr_need_updated = 0;
} break;
case MPP_ENC_GET_RC_API_ALL : {
RcApiQueryAll *query = (RcApiQueryAll *)enc->param;
rc_brief_get_all(query);
} break;
case MPP_ENC_GET_RC_API_BY_TYPE : {
RcApiQueryType *query = (RcApiQueryType *)enc->param;
rc_brief_get_by_type(query);
} break;
case MPP_ENC_SET_RC_API_CFG : {
const RcImplApi *api = (const RcImplApi *)enc->param;
rc_api_add(api);
} break;
case MPP_ENC_GET_RC_API_CURRENT : {
RcApiBrief *dst = (RcApiBrief *)enc->param;
*dst = enc->rc_brief;
} break;
case MPP_ENC_SET_RC_API_CURRENT : {
RcApiBrief *src = (RcApiBrief *)enc->param;
mpp_assert(src->type == enc->coding);
enc->rc_brief = *src;
enc->rc_status.rc_api_user_cfg = 1;
enc->rc_status.rc_api_updated = 1;
} break;
default : {
enc_impl_proc_cfg(enc->impl, enc->cmd, enc->param);
if (MPP_ENC_SET_CODEC_CFG == enc->cmd ||
@ -226,20 +299,128 @@ static void mpp_enc_proc_cfg(MppEncImpl *enc)
}
}
#define RUN_ENC_IMPL_FUNC(func, hal, task, mpp, ret) \
ret = func(hal, task); \
#define RUN_ENC_IMPL_FUNC(func, impl, task, mpp, ret) \
ret = func(impl, task); \
if (ret) { \
mpp_err("mpp %p ##func failed return %d", mpp, ret); \
goto TASK_ERR; \
goto TASK_DONE; \
}
#define RUN_ENC_RC_FUNC(func, ctx, task, mpp, ret) \
ret = func(ctx, task); \
if (ret) { \
mpp_err("mpp %p ##func failed return %d", mpp, ret); \
goto TASK_DONE; \
}
#define RUN_ENC_HAL_FUNC(func, hal, task, mpp, ret) \
ret = func(hal, task); \
if (ret) { \
mpp_err("mpp %p ##func failed return %d", mpp, ret); \
goto TASK_ERR; \
goto TASK_DONE; \
}
static const char *name_of_rc_mode[] = {
"cbr",
"vbr",
"avbr",
};
static void set_rc_cfg(RcCfg *cfg, MppEncCfgSet *cfg_set)
{
MppEncRcCfg *rc = &cfg_set->rc;
MppEncGopRef *ref = &cfg_set->gop_ref;
MppEncPrepCfg *prep = &cfg_set->prep;
MppEncCodecCfg *codec = &cfg_set->codec;
cfg->width = prep->width;
cfg->height = prep->height;
switch (rc->rc_mode) {
case MPP_ENC_RC_MODE_CBR : {
cfg->mode = RC_CBR;
} break;
case MPP_ENC_RC_MODE_VBR : {
cfg->mode = RC_VBR;
} break;
default : {
cfg->mode = RC_AVBR;
} break;
}
cfg->fps.fps_in_flex = rc->fps_in_flex;
cfg->fps.fps_in_num = rc->fps_in_num;
cfg->fps.fps_in_denorm = rc->fps_in_denorm;
cfg->fps.fps_out_flex = rc->fps_out_flex;
cfg->fps.fps_out_num = rc->fps_out_num;
cfg->fps.fps_out_denorm = rc->fps_out_denorm;
cfg->igop = rc->gop;
cfg->bps_target = rc->bps_target;
cfg->bps_max = rc->bps_max;
cfg->bps_min = rc->bps_min;
cfg->stat_times = 1;
cfg->vgop = (ref->gop_cfg_enable) ? (ref->ref_gop_len) : (0);
/* quality configure */
switch (codec->coding) {
case MPP_VIDEO_CodingAVC : {
MppEncH264Cfg *h264 = &codec->h264;
cfg->init_quality = h264->qp_init;
cfg->max_quality = h264->qp_max;
cfg->min_quality = h264->qp_min;
cfg->max_i_quality = h264->qp_max;
cfg->min_i_quality = h264->qp_min;
} break;
case MPP_VIDEO_CodingHEVC : {
MppEncH265Cfg *h265 = &codec->h265;
cfg->init_quality = h265->qp_init;
cfg->max_quality = h265->max_qp;
cfg->min_quality = h265->min_qp;
cfg->max_i_quality = h265->max_i_qp;
cfg->min_i_quality = h265->min_i_qp;
} break;
case MPP_VIDEO_CodingVP8 : {
} break;
case MPP_VIDEO_CodingMJPEG : {
} break;
default : {
mpp_err_f("unsupport coding type %d\n", codec->coding);
} break;
}
if (ref->layer_rc_enable) {
RK_S32 i;
for (i = 0; i < MAX_TEMPORAL_LAYER; i++) {
cfg->layer_bit_prop[i] = ref->layer_weight[i];
}
} else {
cfg->layer_bit_prop[0] = 256;
cfg->layer_bit_prop[1] = 0;
cfg->layer_bit_prop[2] = 0;
cfg->layer_bit_prop[3] = 0;
}
cfg->max_reencode_times = 1;
mpp_log_f("mode: %s\n", name_of_rc_mode[cfg->mode]);
mpp_log_f("bps: [%d : %d : %d]\n",
rc->bps_min, rc->bps_target, rc->bps_max);
mpp_log_f("fps: %s [%d/%d] -> %s [%d/%d]\n",
cfg->fps.fps_in_flex ? "flex" : "fix",
cfg->fps.fps_in_num, cfg->fps.fps_in_denorm,
cfg->fps.fps_out_flex ? "flex" : "fix",
cfg->fps.fps_out_num, cfg->fps.fps_out_denorm);
mpp_log_f("gop: i [%d] v [%d]\n", cfg->igop, cfg->vgop);
}
void *mpp_enc_thread(void *data)
{
Mpp *mpp = (Mpp*)data;
@ -247,6 +428,12 @@ void *mpp_enc_thread(void *data)
EncImpl impl = enc->impl;
MppEncHal hal = enc->enc_hal;
MppThread *thd_enc = enc->thread_enc;
MppEncCfgSet *cfg = &enc->cfg;
MppEncRcCfg *rc_cfg = &cfg->rc;
MppEncGopRef *ref_cfg = &cfg->gop_ref;
MppEncPrepCfg *prep_cfg = &cfg->prep;
EncRcTask *rc_task = &enc->rc_task;
EncFrmStatus *frm = &rc_task->frm;
EncTask task;
HalTaskInfo *task_info = &task.info;
HalEncTask *hal_task = &task_info->enc;
@ -270,15 +457,20 @@ void *mpp_enc_thread(void *data)
thd_enc->wait();
}
// process control first
// 1. process user control
if (enc->cmd_send != enc->cmd_recv) {
enc_dbg_detail("ctrl proc %d cmd %08x\n", enc->cmd_recv, enc->cmd);
mpp_enc_proc_cfg(enc);
sem_post(&enc->enc_ctrl);
enc->cmd_recv++;
enc_dbg_detail("ctrl proc %d done send %d\n", enc->cmd_recv,
enc->cmd_send);
continue;
}
// 2. process reset
if (enc->reset_flag) {
enc_dbg_detail("thread reset start\n");
{
AutoMutex autolock(thd_enc->mutex());
enc->status_flag = 0;
@ -287,10 +479,32 @@ void *mpp_enc_thread(void *data)
AutoMutex autolock(thd_enc->mutex(THREAD_CONTROL));
enc->reset_flag = 0;
sem_post(&enc->enc_reset);
enc_dbg_detail("thread reset done\n");
continue;
}
// 1. check task in
// 3. check and update rate control api
if (!enc->rc_status.rc_api_inited || enc->rc_status.rc_api_updated) {
RcApiBrief *brief = &enc->rc_brief;
if (enc->rc_ctx) {
enc_dbg_detail("rc deinit %p\n", enc->rc_ctx);
rc_deinit(enc->rc_ctx);
enc->rc_ctx = NULL;
}
/* NOTE: default name is NULL */
ret = rc_init(&enc->rc_ctx, enc->coding, brief->name);
if (ret)
mpp_err("enc %p fail to init rc %s\n", enc, brief->name);
else
enc->rc_status.rc_api_inited = 1;
enc_dbg_detail("rc init %p name %s ret %d\n", enc->rc_ctx, brief->name, ret);
enc->rc_status.rc_api_updated = 0;
}
// 4. check input task
if (!task.status.task_in_rdy) {
ret = mpp_port_poll(input, MPP_POLL_NON_BLOCK);
if (ret) {
@ -300,10 +514,10 @@ void *mpp_enc_thread(void *data)
task.status.task_in_rdy = 1;
task.wait.enc_frm_in = 0;
enc_dbg_detail("task in ready\n");
}
enc_dbg_detail("task in ready\n");
// 2. get task out
// 5. check output task
if (!task.status.task_out_rdy) {
ret = mpp_port_poll(output, MPP_POLL_NON_BLOCK);
if (ret) {
@ -313,8 +527,8 @@ void *mpp_enc_thread(void *data)
task.status.task_out_rdy = 1;
task.wait.enc_pkt_out = 0;
enc_dbg_detail("task out ready\n");
}
enc_dbg_detail("task out ready\n");
// get tasks from both input and output
ret = mpp_port_dequeue(input, &task_in);
@ -330,16 +544,43 @@ void *mpp_enc_thread(void *data)
mpp_task_meta_get_frame (task_in, KEY_INPUT_FRAME, &frame);
mpp_task_meta_get_packet(task_in, KEY_OUTPUT_PACKET, &packet);
/* If there is no input frame just return empty packet task */
enc_dbg_detail("task dequeue done frm %p pkt %p\n", frame, packet);
/*
* 6. check empty task for signaling
* If there is no input frame just return empty packet task
*/
if (NULL == frame)
goto TASK_RETURN;
if (NULL == mpp_frame_get_buffer(frame))
goto TASK_RETURN;
// 7. check and update rate control config
if (rc_cfg->change || ref_cfg->change || prep_cfg->change) {
RcCfg usr_cfg;
enc_dbg_detail("rc update cfg start\n");
set_rc_cfg(&usr_cfg, cfg);
ret = rc_update_usr_cfg(enc->rc_ctx, &usr_cfg);
rc_cfg->change = 0;
ref_cfg->change = 0;
prep_cfg->change = 0;
enc_dbg_detail("rc update cfg done\n");
}
// 8. all task ready start encoding one frame
reset_hal_enc_task(hal_task);
reset_enc_rc_task(rc_task);
hal_task->rc_task = rc_task;
frm->seq_idx = task.seq_idx++;
enc_dbg_detail("task seq idx %d start\n", frm->seq_idx);
/*
* 9. check and create packet for output
* if there is available buffer in the input frame do encoding
*/
if (NULL == packet) {
@ -354,15 +595,36 @@ void *mpp_enc_thread(void *data)
/* NOTE: clear length for output */
mpp_packet_set_length(packet, 0);
mpp_buffer_put(buffer);
enc_dbg_detail("create output pkt %p buf %p\n", packet, buffer);
}
mpp_assert(packet);
mpp_packet_set_pts(packet, mpp_frame_get_pts(frame));
// 10. bypass pts to output
{
RK_S64 pts = mpp_frame_get_pts(frame);
mpp_packet_set_pts(packet, pts);
enc_dbg_detail("task %d pts %lld\n", frm->seq_idx, pts);
}
// 11. check frame drop by frame rate conversion
RUN_ENC_RC_FUNC(rc_frm_check_drop, enc->rc_ctx, rc_task, mpp, ret);
enc_dbg_detail("task %d drop %d\n", frm->seq_idx, frm->drop);
if (frm->drop) {
hal_task->valid = 0;
hal_task->length = 0;
goto TASK_DONE;
}
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;
enc_dbg_detail("task %d update header length %d\n",
frm->seq_idx, mpp_packet_get_length(packet));
}
hal_task->frame = frame;
@ -372,34 +634,55 @@ 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
enc_dbg_detail("task %d enc start\n", frm->seq_idx);
RUN_ENC_IMPL_FUNC(enc_impl_start, impl, hal_task, mpp, ret);
/* Invalid task for frame rate drop is returned as error task */
if (!hal_task->valid) {
hal_task->length = 0;
goto TASK_ERR;
}
TASK_REENCODE:
// 14. restore and process dpb
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);
RUN_ENC_IMPL_FUNC(enc_impl_proc_rc, 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);
if (frm->re_dpb_proc)
goto TASK_REENCODE;
enc_dbg_detail("task %d enc proc hal\n", frm->seq_idx);
RUN_ENC_IMPL_FUNC(enc_impl_proc_hal, impl, hal_task, mpp, ret);
enc_dbg_detail("task %d hal get task\n", frm->seq_idx);
RUN_ENC_HAL_FUNC(mpp_enc_hal_get_task, hal, hal_task, mpp, ret);
enc_dbg_detail("task %d rc hal start\n", frm->seq_idx);
RUN_ENC_RC_FUNC(rc_hal_start, enc->rc_ctx, rc_task, mpp, ret);
enc_dbg_detail("task %d hal generate reg\n", frm->seq_idx);
RUN_ENC_HAL_FUNC(mpp_enc_hal_gen_regs, hal, hal_task, mpp, ret);
enc_dbg_detail("task %d hal start\n", frm->seq_idx);
RUN_ENC_HAL_FUNC(mpp_enc_hal_start, hal, hal_task, mpp, ret);
enc_dbg_detail("task %d hal wait\n", frm->seq_idx);
RUN_ENC_HAL_FUNC(mpp_enc_hal_wait, hal, hal_task, mpp, ret);
enc_dbg_detail("task %d rc hal end\n", frm->seq_idx);
RUN_ENC_RC_FUNC(rc_hal_end, enc->rc_ctx, rc_task, mpp, ret);
enc_dbg_detail("task %d hal ret task\n", frm->seq_idx);
RUN_ENC_HAL_FUNC(mpp_enc_hal_ret_task, hal, hal_task, mpp, ret);
enc_dbg_detail("task %d enc update hal\n", frm->seq_idx);
RUN_ENC_IMPL_FUNC(enc_impl_update_hal, impl, hal_task, mpp, ret);
RUN_ENC_IMPL_FUNC(enc_impl_update_rc, impl, hal_task, mpp, ret);
/* If task needs reencode restart from proc_dpb */
if (hal_task->reencode) {
mpp_log_f("reencode time %d\n");
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);
goto TASK_REENCODE;
}
TASK_ERR:
TASK_DONE:
mpp_packet_set_length(packet, hal_task->length);
/*
@ -514,6 +797,10 @@ MPP_RET mpp_enc_init_v2(MppEnc *enc, MppEncCfg *cfg)
p->enc_hal = enc_hal;
p->mpp = cfg->mpp;
/* NOTE: setup configure coding for check */
p->cfg.codec.coding = coding;
p->set.codec.coding = coding;
sem_init(&p->enc_reset, 0, 0);
sem_init(&p->enc_ctrl, 0, 0);

View file

@ -45,11 +45,6 @@ RK_U32 rc_debug = 0;
const static char default_rc_api[] = "default";
MPP_RET rc_api_register(const RcImplApi *api)
{
return RcImplApiService::get_instance()->api_add(api);
}
MPP_RET rc_init(RcCtx *ctx, MppCodingType type, const char *name)
{
MPP_RET ret = MPP_NOK;
@ -62,7 +57,7 @@ MPP_RET rc_init(RcCtx *ctx, MppCodingType type, const char *name)
rc_dbg_func("enter type %x name %s\n", type, name);
const RcImplApi *api = RcImplApiService::get_instance()->api_get(type, name);
RcImplApi *api = RcImplApiService::get_instance()->api_get(type, name);
mpp_assert(api);
@ -122,66 +117,96 @@ MPP_RET rc_update_usr_cfg(RcCtx ctx, RcCfg *cfg)
p->cfg = *cfg;
p->fps = cfg->fps;
if (api && api->init && p->ctx) {
if (api && api->init && p->ctx)
api->init(p->ctx, &p->cfg);
}
rc_dbg_func("leave %p\n", ctx);
return ret;
}
RK_S32 rc_frm_check_drop(RcCtx ctx)
MPP_RET rc_frm_check_drop(RcCtx ctx, EncRcTask *task)
{
MppRcImpl *p = (MppRcImpl *)ctx;
RcFpsCfg *cfg = &p->fps;
RK_S32 frm_cnt = p->frm_cnt;
RK_S32 rate_in = cfg->fps_in_num * cfg->fps_out_denorm;
RK_S32 rate_out = cfg->fps_out_num * cfg->fps_in_denorm;
RK_S32 drop = 0;
const RcImplApi *api = p->api;
MPP_RET ret = MPP_OK;
rc_dbg_func("enter %p\n", ctx);
mpp_assert(cfg->fps_in_denorm >= 1);
mpp_assert(cfg->fps_out_denorm >= 1);
mpp_assert(rate_in >= rate_out);
if (api && api->check_drop && p->ctx && task) {
ret = api->check_drop(p->ctx, task);
return ret;
} else {
RcFpsCfg *cfg = &p->fps;
RK_S32 frm_cnt = p->frm_cnt;
RK_S32 rate_in = cfg->fps_in_num * cfg->fps_out_denorm;
RK_S32 rate_out = cfg->fps_out_num * cfg->fps_in_denorm;
RK_S32 drop = 0;
// frame counter is inited to (rate_in - rate_out) to encode first frame
if (frm_cnt < 0)
frm_cnt = rate_in - rate_out;
mpp_assert(cfg->fps_in_denorm >= 1);
mpp_assert(cfg->fps_out_denorm >= 1);
mpp_assert(rate_in >= rate_out);
frm_cnt += rate_out;
// frame counter is inited to (rate_in - rate_out) to encode first frame
if (frm_cnt < 0)
frm_cnt = rate_in - rate_out;
if (frm_cnt < rate_in)
drop = 1;
else
frm_cnt -= rate_in;
frm_cnt += rate_out;
p->frm_cnt = frm_cnt;
if (frm_cnt < rate_in)
drop = 1;
else
frm_cnt -= rate_in;
rc_dbg_func("leave %p drop %d\n", ctx, drop);
p->frm_cnt = frm_cnt;
task->frm.drop = drop;
}
return drop;
rc_dbg_func("leave %p drop %d\n", ctx, task->frm.drop);
return ret;
}
MPP_RET rc_frm_start(RcCtx ctx, RcHalCfg *cfg, EncFrmStatus *frm)
MPP_RET rc_frm_start(RcCtx ctx, EncRcTask *task)
{
MppRcImpl *p = (MppRcImpl *)ctx;
const RcImplApi *api = p->api;
if (!api || !api->start || !p->ctx)
if (!api || !api->frm_start || !p->ctx || !task)
return MPP_OK;
return api->start(p->ctx, cfg, frm);
return api->frm_start(p->ctx, task);
}
MPP_RET rc_frm_end(RcCtx ctx, RcHalCfg *cfg)
MPP_RET rc_frm_end(RcCtx ctx, EncRcTask *task)
{
MppRcImpl *p = (MppRcImpl *)ctx;
const RcImplApi *api = p->api;
if (!api || !api->end || !p->ctx)
if (!api || !api->frm_end || !p->ctx || !task)
return MPP_OK;
return api->end(p->ctx, cfg);
return api->frm_end(p->ctx, task);
}
MPP_RET rc_hal_start(RcCtx ctx, EncRcTask *task)
{
MppRcImpl *p = (MppRcImpl *)ctx;
const RcImplApi *api = p->api;
if (!api || !api->hal_start || !p->ctx || !task)
return MPP_OK;
return api->hal_start(p->ctx, task);
}
MPP_RET rc_hal_end(RcCtx ctx, EncRcTask *task)
{
MppRcImpl *p = (MppRcImpl *)ctx;
const RcImplApi *api = p->api;
if (!api || !api->hal_end || !p->ctx || !task)
return MPP_OK;
return api->hal_end(p->ctx, task);
}

View file

@ -33,9 +33,9 @@
#define rc_dbg_func(fmt, ...) rc_dbg_f(RC_DBG_FUNCTION, fmt, ## __VA_ARGS__)
#define rc_dbg_impl(fmt, ...) rc_dbg_f(RC_DBG_API_IMPL, fmt, ## __VA_ARGS__)
#define rc_dbg_fps(fmt, ...) rc_dbg(RC_DBG_FPS, fmt, ## __VA_ARGS__)
#define rc_dbg_bps(fmt, ...) rc_dbg(RC_DBG_BPS, fmt, ## __VA_ARGS__)
#define rc_dbg_rc(fmt, ...) rc_dbg(RC_DBG_RC, fmt, ## __VA_ARGS__)
#define rc_dbg_fps(fmt, ...) rc_dbg_f(RC_DBG_FPS, fmt, ## __VA_ARGS__)
#define rc_dbg_bps(fmt, ...) rc_dbg_f(RC_DBG_BPS, fmt, ## __VA_ARGS__)
#define rc_dbg_rc(fmt, ...) rc_dbg_f(RC_DBG_RC, fmt, ## __VA_ARGS__)
#define rc_dbg_cfg(fmt, ...) rc_dbg(RC_DBG_CFG, fmt, ## __VA_ARGS__)
#define rc_dbg_vbv(fmt, ...) rc_dbg(RC_DBG_VBV, fmt, ## __VA_ARGS__)

View file

@ -37,9 +37,22 @@ typedef struct RcImplApiNode_t {
struct list_head list;
char name[32];
MppCodingType type;
RcApiBrief brief;
RcImplApi api;
} RcImplApiNode;
static void set_node_api(RcImplApiNode *node, const RcImplApi *api)
{
node->api = *api;
node->type = api->type;
strncpy(node->name, api->name, sizeof(node->name) - 1);
node->api.name = api->name;
node->brief.type = api->type;
node->brief.name = api->name;
}
RcImplApiService::RcImplApiService()
{
RK_U32 i;
@ -75,30 +88,39 @@ MPP_RET RcImplApiService::api_add(const RcImplApi *api)
return MPP_NOK;
}
RcImplApiNode *node = mpp_malloc(RcImplApiNode, 1);
if (NULL == node) {
mpp_err_f("failed to create api node\n");
return MPP_NOK;
/* search for same node for replacement */
RcImplApiNode *node = NULL;
RcImplApi *node_api = api_get(api->type, api->name);
if (NULL == node_api) {
node = mpp_malloc(RcImplApiNode, 1);
if (NULL == node) {
mpp_err_f("failed to create api node\n");
return MPP_NOK;
}
INIT_LIST_HEAD(&node->list);
list_add_tail(&node->list, &mApis);
mApiCount++;
rc_dbg_impl("rc impl %s type %x is added\n", api->name, api->type);
} else {
node = container_of(node_api, RcImplApiNode, api);
rc_dbg_impl("rc impl %s type %x is updated\n", api->name, api->type);
}
INIT_LIST_HEAD(&node->list);
node->api = *api;
node->type = api->type;
strncpy(node->name, api->name, sizeof(node->name) - 1);
node->api.name = api->name;
rc_dbg_impl("rc impl %s type %x is added\n", api->name, api->type);
list_add_tail(&node->list, &mApis);
mApiCount++;
set_node_api(node, api);
return MPP_OK;
}
const RcImplApi *RcImplApiService::api_get(MppCodingType type, const char *name)
RcImplApi *RcImplApiService::api_get(MppCodingType type, const char *name)
{
AutoMutex auto_lock(get_lock());
if (!mApiCount)
return NULL;
if (name) {
RcImplApiNode *pos, *n;
@ -106,12 +128,99 @@ const RcImplApi *RcImplApiService::api_get(MppCodingType type, const char *name)
if (type == pos->type &&
!strncmp(name, pos->name, sizeof(pos->name) - 1)) {
rc_dbg_impl("rc impl %s is selected\n", pos->name);
return (const RcImplApi *)&pos->api;
return &pos->api;
}
}
}
mpp_err_f("failed to find rc impl %s\n", name);
rc_dbg_impl("failed to find rc impl %s type %x\n", name, type);
return NULL;
}
MPP_RET RcImplApiService::api_get_all(RcApiBrief *brief, RK_S32 *count, RK_S32 max_count)
{
RK_S32 cnt = 0;
RcImplApiNode *pos, *n;
AutoMutex auto_lock(get_lock());
list_for_each_entry_safe(pos, n, &mApis, RcImplApiNode, list) {
if (cnt >= max_count)
break;
brief[cnt++] = pos->brief;
}
*count = cnt;
return MPP_OK;
}
MPP_RET RcImplApiService::api_get_by_type(RcApiBrief *brief, RK_S32 *count,
RK_S32 max_count, MppCodingType type)
{
RK_S32 cnt = 0;
RcImplApiNode *pos, *n;
AutoMutex auto_lock(get_lock());
list_for_each_entry_safe(pos, n, &mApis, RcImplApiNode, list) {
if (cnt >= max_count)
break;
if (pos->type != type)
continue;
brief[cnt++] = pos->brief;
}
*count = cnt;
return MPP_OK;
}
MPP_RET rc_api_add(const RcImplApi *api)
{
return RcImplApiService::get_instance()->api_add(api);
}
MPP_RET rc_brief_get_all(RcApiQueryAll *query)
{
if (NULL == query) {
mpp_err_f("invalide NULL query input\n");
return MPP_ERR_NULL_PTR;
}
RcApiBrief *brief = query->brief;
RK_S32 *count = &query->count;
RK_S32 max_count = query->max_count;
if (NULL == brief || max_count <= 0) {
mpp_err_f("invalide brief buffer %p max count %d\n", brief, max_count);
return MPP_NOK;
}
return RcImplApiService::get_instance()->api_get_all(brief, count, max_count);
}
MPP_RET rc_brief_get_by_type(RcApiQueryType *query)
{
if (NULL == query) {
mpp_err_f("invalide NULL query input\n");
return MPP_ERR_NULL_PTR;
}
RcApiBrief *brief = query->brief;
RK_S32 *count = &query->count;
RK_S32 max_count = query->max_count;
MppCodingType type = query->type;
if (NULL == brief || max_count <= 0) {
mpp_err_f("invalide brief buffer %p max count %d type %x\n",
brief, max_count, type);
return MPP_NOK;
}
return RcImplApiService::get_instance()->api_get_by_type(brief, count, max_count, type);
}

View file

@ -18,7 +18,11 @@
#define __RC_IMPL_H__
#include "mpp_list.h"
#include "rc_api.h"
#include "mpp_rc_api.h"
#define MAX_RC_API_COUNT 32
#ifdef __cplusplus
class RcImplApiService
{
@ -44,8 +48,22 @@ public:
return &lock;
}
MPP_RET api_add(const RcImplApi *api);
const RcImplApi *api_get(MppCodingType type, const char *name);
MPP_RET api_add(const RcImplApi *api);
RcImplApi *api_get(MppCodingType type, const char *name);
MPP_RET api_get_all(RcApiBrief *brief, RK_S32 *count, RK_S32 max_count);
MPP_RET api_get_by_type(RcApiBrief *brief, RK_S32 *count,
RK_S32 max_count, MppCodingType type);
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* __RC_IMPL_H__ */

View file

@ -48,51 +48,55 @@ RK_S32 tab_lnx[64] = {
};
typedef struct RcModelV2Ctx_t {
RcCfg usr_cfg;
RcHalCfg hal_cfg;
RcCfg usr_cfg;
EncRcTaskInfo hal_cfg;
RK_U32 frame_type;
RK_U32 last_frame_type;
RK_S64 gop_total_bits;
RK_U32 bit_per_frame;
RK_U32 frame_type;
RK_U32 last_frame_type;
RK_S64 gop_total_bits;
RK_U32 bit_per_frame;
MppDataV2 *i_bit;
RK_U32 i_sumbits;
RK_U32 i_scale;
MppDataV2 *i_bit;
RK_U32 i_sumbits;
RK_U32 i_scale;
MppDataV2 *idr_bit;
RK_U32 idr_sumbits;
RK_U32 idr_scale;
MppDataV2 *idr_bit;
RK_U32 idr_sumbits;
RK_U32 idr_scale;
MppDataV2 *p_bit;
RK_U32 p_sumbits;
RK_U32 p_scale;
MppDataV2 *p_bit;
RK_U32 p_sumbits;
RK_U32 p_scale;
MppDataV2 *pre_p_bit;
MppDataV2 *pre_p_bit;
RK_S32 target_bps;
RK_S32 pre_target_bits;
RK_S32 pre_real_bits;
RK_S32 frm_bits_thr;
RK_S32 ins_bps;
RK_S32 last_inst_bps;
RK_U32 water_level_thr;
RK_S32 target_bps;
RK_S32 pre_target_bits;
RK_S32 pre_real_bits;
RK_S32 frm_bits_thr;
RK_S32 ins_bps;
RK_S32 last_inst_bps;
RK_U32 water_level_thr;
MppDataV2 *stat_bits;
MppDataV2 *stat_rate;
RK_S32 stat_watl_thrd;
RK_S32 stat_watl;
RK_S32 stat_last_watl;
MppDataV2 *stat_bits;
MppDataV2 *stat_rate;
RK_S32 stat_watl_thrd;
RK_S32 stat_watl;
RK_S32 stat_last_watl;
RK_S32 next_i_ratio; // scale 64
RK_S32 next_ratio; // scale 64
RK_S32 pre_i_qp;
RK_S32 pre_p_qp;
RK_S32 scale_qp; // scale 64
MppDataV2 *means_qp;
RK_S32 next_i_ratio; // scale 64
RK_S32 next_ratio; // scale 64
RK_S32 pre_i_qp;
RK_S32 pre_p_qp;
RK_S32 scale_qp; // scale 64
MppDataV2 *means_qp;
RK_U32 frm_num;
RK_S32 reenc_cnt;
/*qp decision*/
RK_S32 cur_scale_qp;
RK_S32 start_qp;
RK_S32 prev_quality;
RK_S32 reenc_cnt;
} RcModelV2Ctx;
MPP_RET bits_model_deinit(RcModelV2Ctx *ctx)
@ -149,7 +153,6 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx)
if (ctx->usr_cfg.max_i_bit_prop <= 0)
ctx->usr_cfg.max_i_bit_prop = 20;
rc_dbg_rc("gop_len %d ctx->usr_cfg.stat_times %d \n", gop_len, ctx->usr_cfg.stat_times);
stat_len = fps->fps_in_num * ctx->usr_cfg.stat_times;
if (ctx->usr_cfg.mode == RC_CBR) {
target_bps = ctx->usr_cfg.bps_target;
@ -163,8 +166,6 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx)
gop_bits = fps->fps_in_num * target_bps * fps->fps_out_denorm;
ctx->gop_total_bits = gop_bits / fps->fps_out_num;
mpp_log("gop_total_bits = %lld, gop_len %d fps->fps_out_denorm %d, fps->fps_out_num %d", ctx->gop_total_bits, gop_len,
fps->fps_out_denorm, fps->fps_out_num);
bits_model_deinit(ctx);
mpp_data_init_v2(&ctx->i_bit, I_WINDOW_LEN);
@ -206,7 +207,9 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx)
ctx->stat_watl_thrd = total_stat_bits;
ctx->stat_watl = total_stat_bits >> 3;
mpp_log("bit_per_frame = %d", ctx->bit_per_frame);
rc_dbg_rc("gop %d total bit %lld per_frame %d statistics time %d second\n",
ctx->usr_cfg.igop, ctx->gop_total_bits, ctx->bit_per_frame,
ctx->usr_cfg.stat_times);
if (gop_len <= 1)
p_bit = ctx->gop_total_bits * 16;
@ -220,7 +223,8 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx)
mpp_data_reset_v2(ctx->i_bit, p_bit * ctx->i_scale / 16);
ctx->i_sumbits = 2 * p_bit * ctx->i_scale / 16;
rc_dbg_rc("ctx->p_sumbits %d,ctx->i_sumbits %d", ctx->p_sumbits, ctx->i_sumbits);
rc_dbg_rc("p_sumbits %d i_sumbits %d\n", ctx->p_sumbits, ctx->i_sumbits);
rc_dbg_func("leave %p\n", ctx);
return MPP_OK;
@ -231,6 +235,7 @@ MPP_RET bits_model_update(RcModelV2Ctx *ctx, RK_S32 real_bit)
RK_S32 water_level = 0, last_water_level;
rc_dbg_func("enter %p\n", ctx);
mpp_data_update_v2(ctx->stat_rate, real_bit != 0);
mpp_data_update_v2(ctx->stat_bits, real_bit);
last_water_level = ctx->stat_last_watl;
@ -249,9 +254,9 @@ MPP_RET bits_model_update(RcModelV2Ctx *ctx, RK_S32 real_bit)
case INTRA_FRAME: {
mpp_data_update_v2(ctx->i_bit, real_bit);
ctx->i_sumbits = mpp_data_sum_v2(ctx->i_bit);
rc_dbg_rc("ctx->i_sumbits %d ctx->p_sumbits %d", ctx->i_sumbits, ctx->p_sumbits);
ctx->i_scale = 80 * ctx->i_sumbits / (2 * ctx->p_sumbits);
rc_dbg_rc("ctx->i_scale %d", ctx->i_scale);
rc_dbg_rc("i_sumbits %d p_sumbits %d i_scale %d\n",
ctx->i_sumbits, ctx->p_sumbits, ctx->i_scale);
} break;
case INTER_P_FRAME: {
@ -268,7 +273,7 @@ MPP_RET bits_model_update(RcModelV2Ctx *ctx, RK_S32 real_bit)
return MPP_OK;
}
MPP_RET bits_model_alloc(RcModelV2Ctx *ctx, RcHalCfg *cfg)
MPP_RET bits_model_alloc(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg)
{
RK_U32 max_i_prop = ctx->usr_cfg.max_i_bit_prop * 16;
RK_U32 gop_len = ctx->usr_cfg.igop;
@ -399,7 +404,7 @@ MPP_RET calc_cbr_ratio(RcModelV2Ctx *ctx)
return MPP_OK;
}
MPP_RET reenc_calc_cbr_ratio(RcModelV2Ctx *ctx, RcHalCfg *cfg)
MPP_RET reenc_calc_cbr_ratio(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg)
{
RK_S32 stat_time = ctx->usr_cfg.stat_times;
RK_S32 last_ins_bps = mpp_data_sum_v2(ctx->stat_bits) / stat_time;
@ -510,7 +515,7 @@ MPP_RET calc_vbr_ratio(RcModelV2Ctx *ctx)
return MPP_OK;
}
MPP_RET reenc_calc_vbr_ratio(RcModelV2Ctx *ctx, RcHalCfg *cfg)
MPP_RET reenc_calc_vbr_ratio(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg)
{
RK_S32 stat_time = ctx->usr_cfg.stat_times;
RK_S32 last_ins_bps = mpp_data_sum_v2(ctx->stat_bits) / stat_time;
@ -557,7 +562,7 @@ MPP_RET bits_mode_reset(RcModelV2Ctx *ctx)
return MPP_OK;
}
MPP_RET check_re_enc(RcModelV2Ctx *ctx, RcHalCfg *cfg)
MPP_RET check_re_enc(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg)
{
RK_S32 frame_type = ctx->frame_type;
RK_S32 i_flag = 0;
@ -633,47 +638,181 @@ MPP_RET rc_model_v2_deinit(void *ctx)
return MPP_OK;
}
MPP_RET rc_model_v2_start(void *ctx, RcHalCfg *cfg, EncFrmStatus *frm)
MPP_RET rc_model_v2_start(void *ctx, EncRcTask *task)
{
rc_dbg_func("enter %p\n", ctx);
RcModelV2Ctx *p = (RcModelV2Ctx*)ctx;
EncFrmStatus *frm = &task->frm;
EncRcTaskInfo *info = &task->info;
rc_dbg_func("enter %p\n", ctx);
cfg->need_reenc = 0;
if (frm->reencode || p->usr_cfg.mode == RC_FIXQP) {
frm->reencode = 0;
return MPP_OK;
}
if (frm->is_intra) {
p->frame_type = INTRA_FRAME;
} else {
p->frame_type = INTER_P_FRAME;
}
bits_model_alloc(p, cfg);
p->frame_type = (frm->is_intra) ? (INTRA_FRAME) : (INTER_P_FRAME);
rc_dbg_rc("cfg->bit_target = %d", cfg->bit_target);
cfg->next_ratio = 0;
/* bitrate allocation */
bits_model_alloc(p, info);
p->next_ratio = 0;
if (p->last_frame_type == INTRA_FRAME) {
calc_next_i_ratio(p);
cfg->next_i_ratio = p->next_i_ratio;
}
if (p->frm_num) {
if (frm->seq_idx) {
if (p->usr_cfg.mode == RC_CBR) {
calc_cbr_ratio(p);
} else {
calc_vbr_ratio(p);
}
}
cfg->next_ratio = p->next_ratio;
p->frm_num++;
/* quality determination */
if (!frm->seq_idx)
info->quality_target = -1;
info->quality_max = p->usr_cfg.max_quality;
info->quality_min = p->usr_cfg.min_quality;
rc_dbg_rc("seq_idx %d intra %d\n", frm->seq_idx, frm->is_intra);
rc_dbg_rc("bitrate [%d : %d : %d]\n", info->bit_min, info->bit_target, info->bit_max);
rc_dbg_rc("quality [%d : %d : %d]\n", info->quality_min, info->quality_target, info->quality_max);
p->reenc_cnt = 0;
rc_dbg_func("leave %p\n", ctx);
return MPP_OK;
}
static RK_U32 mb_num[12] = {
0, 200, 700, 1200,
2000, 4000, 8000, 16000,
20000, 20000, 20000, 20000,
};
static RK_U32 tab_bit[12] = {
0xEC4, 0xDF2, 0xC4E, 0xB7C,
0xAAA, 0xEC4, 0x834, 0x690,
0x834, 0x834, 0x834, 0x834,
};
static RK_U8 qp_table[96] = {
0xF, 0xF, 0xF, 0xF, 0xF, 0x10, 0x12, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E,
0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22,
0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25,
0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29,
0x29, 0x29, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2B,
0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C,
0x2C, 0x2C, 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D,
};
static RK_S32 cal_first_i_start_qp(RK_S32 target_bit, RK_U32 total_mb)
{
RK_S32 cnt = 0;
RK_S32 index;
RK_S32 i;
for (i = 0; i < 11; i++) {
if (mb_num[i] > total_mb)
break;
cnt++;
}
index = (total_mb * tab_bit[cnt] - 300) / target_bit; //
index = mpp_clip(index, 4, 95);
return qp_table[index];
}
MPP_RET rc_model_v2_hal_start(void *ctx, EncRcTask *task)
{
RcModelV2Ctx *p = (RcModelV2Ctx *)ctx;
EncFrmStatus *frm = &task->frm;
EncRcTaskInfo *info = &task->info;
RK_S32 mb_w = MPP_ALIGN(p->usr_cfg.width, 16) / 16;
RK_S32 mb_h = MPP_ALIGN(p->usr_cfg.height, 16) / 16;
RK_S32 bit_min = info->bit_min;
RK_S32 bit_max = info->bit_max;
RK_S32 bit_target = info->bit_target;
RK_S32 quality_min = info->quality_min;
RK_S32 quality_max = info->quality_max;
RK_S32 quality_target = info->quality_target;
rc_dbg_func("enter p %p task %p\n", p, task);
rc_dbg_rc("seq_idx %d intra %d\n", frm->seq_idx, frm->is_intra);
/* setup quality parameters */
if (!frm->seq_idx && frm->is_intra) {
if (info->quality_target < 0) {
if (info->bit_target) {
p->start_qp = cal_first_i_start_qp(info->bit_target, mb_w * mb_h);
p->cur_scale_qp = (p->start_qp) << 6;
} else {
mpp_log("fix qp case but init qp no set");
info->quality_target = 26;
p->start_qp = 26;
p->cur_scale_qp = (p->start_qp) << 6;
}
} else {
p->start_qp = info->quality_target;
p->cur_scale_qp = (p->start_qp) << 6;
}
p->cur_scale_qp = mpp_clip(p->cur_scale_qp, (info->quality_min << 6), (info->quality_max << 6));
p->pre_i_qp = p->cur_scale_qp >> 6;
p->pre_p_qp = p->cur_scale_qp >> 6;
} else {
RK_S32 qp_scale = p->cur_scale_qp + p->next_ratio;
RK_S32 start_qp = 0;
if (frm->is_intra) {
//qp_scale = mpp_clip(qp_scale, (h265->min_i_qp << 6), (h265->max_i_qp << 6));
qp_scale = mpp_clip(qp_scale, (info->quality_min << 6), (info->quality_max << 6));
start_qp = ((p->pre_i_qp + ((qp_scale + p->next_i_ratio) >> 6)) >> 1);
start_qp = mpp_clip(start_qp, info->quality_min, info->quality_max);
p->pre_i_qp = start_qp;
p->start_qp = start_qp;
p->cur_scale_qp = qp_scale;
} else {
qp_scale = mpp_clip(qp_scale, (info->quality_min << 6), (info->quality_max << 6));
p->cur_scale_qp = qp_scale;
p->start_qp = qp_scale >> 6;
}
}
info->quality_target = p->start_qp;
rc_dbg_rc("bitrate [%d : %d : %d] -> [%d : %d : %d]\n",
bit_min, bit_target, bit_max,
info->bit_min, info->bit_target, info->bit_max);
rc_dbg_rc("quality [%d : %d : %d] -> [%d : %d : %d]\n",
quality_min, quality_target, quality_max,
info->quality_min, info->quality_target, info->quality_max);
rc_dbg_func("leave %p\n", p);
return MPP_OK;
}
MPP_RET rc_model_v2_hal_end(void *ctx, EncRcTask *task)
{
rc_dbg_func("enter ctx %p task %p\n", ctx, task);
rc_dbg_func("leave %p\n", ctx);
return MPP_OK;
}
MPP_RET rc_model_v2_end(void *ctx, RcHalCfg *cfg)
MPP_RET rc_model_v2_end(void *ctx, EncRcTask *task)
{
RcModelV2Ctx *p = (RcModelV2Ctx *)ctx;
EncRcTaskInfo *cfg = (EncRcTaskInfo *)&task->info;
EncFrmStatus *frm = &task->frm;
rc_dbg_func("enter ctx %p cfg %p\n", ctx, cfg);
if (p->usr_cfg.mode == RC_FIXQP) {
@ -689,8 +828,8 @@ MPP_RET rc_model_v2_end(void *ctx, RcHalCfg *cfg)
if (p->next_ratio != 0) {
p->reenc_cnt++;
cfg->next_ratio = p->next_ratio;
cfg->need_reenc = 1;
frm->reencode = 1;
frm->reencode_times++;
}
} else {
rc_dbg_rc("bits_mode_update real_bit %d", cfg->bit_real);
@ -711,8 +850,11 @@ const RcImplApi default_h264e = {
sizeof(RcModelV2Ctx),
rc_model_v2_init,
rc_model_v2_deinit,
NULL,
rc_model_v2_start,
rc_model_v2_end,
rc_model_v2_hal_start,
rc_model_v2_hal_end,
};
const RcImplApi default_h265e = {
@ -721,6 +863,9 @@ const RcImplApi default_h265e = {
sizeof(RcModelV2Ctx),
rc_model_v2_init,
rc_model_v2_deinit,
NULL,
rc_model_v2_start,
rc_model_v2_end,
rc_model_v2_hal_start,
rc_model_v2_hal_end,
};

View file

@ -16,7 +16,7 @@
#ifndef __RC_MODEL_V2_H__
#define __RC_MODEL_V2_H__
#include "rc_api.h"
#include "mpp_rc_api.h"
#ifdef __cplusplus
extern "C" {

View file

@ -21,3 +21,6 @@ endmacro()
# mpp rc unit test
add_mpp_rc_test(rc_base)
# mpp rc api test
add_mpp_rc_test(rc_api)

View file

@ -0,0 +1,85 @@
/*
* Copyright 2015 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define MODULE_TAG "mpp_api_test"
#include <stdlib.h>
#include "mpp_log.h"
#include "mpp_rc_api.h"
#define MAX_QUERY_COUNT 16
const RcImplApi test_h264_api = {
"test_h264e_rc",
MPP_VIDEO_CodingAVC,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
const RcImplApi test_h265_api = {
"test_h265e_rc",
MPP_VIDEO_CodingHEVC,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
int main()
{
RcApiQueryAll query;
RcApiBrief briefs[MAX_QUERY_COUNT];
RK_S32 i;
mpp_log("rc api test start\n");
query.brief = briefs;
query.max_count = MAX_QUERY_COUNT;
query.count = 0;
rc_brief_get_all(&query);
mpp_log("default rc api query result:\n");
for (i = 0; i < query.count; i++)
mpp_log("rc api %s type %x\n", briefs[i].name, briefs[i].type);
mpp_log("add test rc api\n");
rc_api_add(&test_h264_api);
rc_api_add(&test_h265_api);
rc_brief_get_all(&query);
mpp_log("rc api query result after adding\n");
for (i = 0; i < query.count; i++)
mpp_log("rc api %s type %x\n", briefs[i].name, briefs[i].type);
mpp_log("mpp rc api test done\n");
return 0;
}

View file

@ -17,8 +17,8 @@
#ifndef __H264E_SYNTAX_NEW_H__
#define __H264E_SYNTAX_NEW_H__
#include "mpp_rc_api.h"
#include "h264_syntax.h"
#include "rc_api.h"
typedef enum H264eSyntaxType_e {
H264E_SYN_CFG,
@ -311,10 +311,6 @@ typedef struct H264eFrmInfo_s {
RK_S32 curr_idx;
RK_S32 refr_idx;
// current frame rate control and dpb status info
RcHalCfg rc_cfg;
EncFrmStatus status;
RK_S32 usage[H264E_MAX_REFS_CNT + 1];
} H264eFrmInfo;

View file

@ -211,8 +211,6 @@ typedef struct H265eFrmInfo_s {
RK_S32 frame_type;
RK_S32 last_frame_type;
RcHalCfg rc_cfg;
EncFrmStatus status;
RK_S32 usage[MAX_REFS + 1];
} H265eFrmInfo;

View file

@ -19,6 +19,7 @@
#define __HAL_ENC_TASK__
#include "hal_task_defs.h"
#include "mpp_rc_defs.h"
#define HAL_ENC_TASK_ERR_INIT 0x00000001
#define HAL_ENC_TASK_ERR_ALLOC 0x00000010
@ -28,12 +29,14 @@
#define HAL_ENC_TASK_ERR_WAIT 0x00100000
typedef struct HalEncTaskFlag_t {
RK_U32 err;
RK_U32 err;
} HalEncTaskFlag;
typedef struct HalEncTask_t {
RK_U32 valid;
RK_U32 reencode;
// rate control data channel
EncRcTask *rc_task;
// current tesk protocol syntax information
MppSyntax syntax;

View file

@ -63,7 +63,7 @@ typedef struct HalH264eVepu541Ctx_t {
RcSyntax *rc_syn;
/* syntax for output to enc_impl */
RcHalCfg hal_rc_cfg;
EncRcTaskInfo hal_rc_cfg;
/* roi */
MppEncROICfg *roi_data;
@ -428,7 +428,6 @@ static void setup_vepu541_codec(Vepu541H264eRegSet *regs, SynH264eSps *sps,
regs->reg013.cur_frm_ref = slice->nal_reference_idc > 0;
regs->reg013.bs_scp = 1;
regs->reg013.lamb_mod_sel = (slice->slice_type == H264_I_SLICE) ? 0 : 1;
regs->reg013.pic_qp = pps->pic_init_qp + slice->qp_delta;
regs->reg013.atr_thd_sel = 0;
regs->reg013.node_int = 0;
@ -534,14 +533,19 @@ static void setup_vepu541_rdo_pred(Vepu541H264eRegSet *regs, SynH264eSps *sps,
hal_h264e_dbg_func("leave\n");
}
static void setup_vepu541_rc_base(Vepu541H264eRegSet *regs, SynH264eSps *sps)
static void setup_vepu541_rc_base(Vepu541H264eRegSet *regs, SynH264eSps *sps,
EncRcTask *rc_task)
{
RK_U32 qp_min = 9;
RK_U32 qp_max = 51;
EncRcTaskInfo *rc_info = &rc_task->info;
RK_U32 qp_target = rc_info->quality_target;
RK_U32 qp_min = rc_info->quality_max;
RK_U32 qp_max = rc_info->quality_min;
RK_U32 qpmap_mode = 1;
hal_h264e_dbg_func("enter\n");
regs->reg013.pic_qp = qp_target;
regs->reg050.rc_en = 0;
regs->reg050.aq_en = 0;
regs->reg050.aq_mode = 0;
@ -1100,7 +1104,7 @@ static MPP_RET hal_h264e_vepu541_gen_regs(void *hal, HalEncTask *task)
setup_vepu541_prep(regs, &ctx->cfg->prep);
setup_vepu541_codec(regs, sps, pps, slice);
setup_vepu541_rdo_pred(regs, sps, pps, slice);
setup_vepu541_rc_base(regs, sps);
setup_vepu541_rc_base(regs, sps, task->rc_task);
setup_vepu541_orig(regs, ctx->dev_ctx, &ctx->dev_patch, task->frame);
setup_vepu541_roi(regs, ctx);
setup_vepu541_recn_refr(regs, ctx->frms, ctx->hw_recn,

View file

@ -29,7 +29,6 @@
#include "h265e_syntax_new.h"
#include "hal_h265e_api.h"
#include "hal_h265e_vepu541.h"
#include "rc_api.h"
#include "vepu541_common.h"
#include "rkv_enc_def.h"
#include "mpp_enc_hal.h"
@ -77,11 +76,6 @@ typedef struct H265eV541HalContext_t {
RK_U32 frame_cnt_send_ready;
RK_U32 num_frames_to_send;
/*qp decision*/
RK_S32 cur_scale_qp;
RK_S32 pre_i_qp;
RK_S32 pre_p_qp;
RK_S32 start_qp;
RK_S32 frame_type;
RK_S32 last_frame_type;
@ -200,44 +194,6 @@ RK_U32 lamd_modb_qp[52] = {
0x00700000, 0x00890000, 0x00b00000, 0x00e00000
};
static RK_U32 mb_num[12] = {
0x0, 0xc8, 0x2bc, 0x4b0,
0x7d0, 0xfa0, 0x1f40, 0x3e80,
0x4e20, 0x4e20, 0x4e20, 0x4e20,
};
static RK_U32 tab_bit[12] = {
0xEC4, 0xDF2, 0xC4E, 0xB7C, 0xAAA, 0xEC4, 0x834, 0x690, 0x834, 0x834, 0x834, 0x834,
};
static RK_U8 qp_table[96] = {
0xF, 0xF, 0xF, 0xF, 0xF, 0x10, 0x12, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E,
0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22,
0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25,
0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29,
0x29, 0x29, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2B,
0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C,
0x2C, 0x2C, 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D,
};
static RK_S32 cal_first_i_start_qp(RK_S32 target_bit, RK_U32 total_mb)
{
RK_S32 cnt = 0, index, i;
for (i = 0; i < 11; i++) {
if (mb_num[i] > total_mb)
break;
cnt++;
}
index = (total_mb * tab_bit[cnt] - 300) / target_bit; //
index = mpp_clip(index, 4, 95);
return qp_table[index];
}
static MPP_RET vepu541_h265_free_buffers(H265eV541HalContext *ctx)
{
RK_S32 k = 0;
@ -382,7 +338,7 @@ MPP_RET hal_h265e_v541_init(void *hal, MppEncHalCfg *cfg)
ctx->ioctl_output = mpp_calloc(H265eV541IoctlOutput, 1);
ctx->regs = mpp_calloc(H265eV541RegSet, RKVE_LINKTABLE_FRAME_NUM);
ctx->l2_regs = mpp_calloc(H265eV541L2RegSet, RKVE_LINKTABLE_FRAME_NUM);
ctx->rc_hal_cfg = mpp_calloc(RcHalCfg, RKVE_LINKTABLE_FRAME_NUM);
ctx->rc_hal_cfg = mpp_calloc(EncRcTaskInfo, RKVE_LINKTABLE_FRAME_NUM);
ctx->buffers = mpp_calloc(h265e_v541_buffers, RKVE_LINKTABLE_FRAME_NUM);
ctx->input_fmt = mpp_calloc(VepuFmtCfg, 1);
ctx->set = cfg->set;
@ -567,56 +523,19 @@ vepu541_h265_set_roi_regs(H265eV541HalContext *ctx, H265eV541RegSet *regs)
return MPP_OK;
}
static MPP_RET vepu541_h265_set_rc_regs(H265eV541HalContext *ctx, H265eV541RegSet *regs, H265eSyntax_new *syn)
static MPP_RET vepu541_h265_set_rc_regs(H265eV541HalContext *ctx, H265eV541RegSet *regs, HalEncTask *task)
{
H265eSyntax_new *syn = (H265eSyntax_new *)task->syntax.data;
H265eFrmInfo *frms = &syn->frms;
EncRcTaskInfo *rc_cfg = &task->rc_task->info;
MppEncCfgSet *cfg = ctx->cfg;
MppEncRcCfg *rc = &cfg->rc;
RcHalCfg *rc_cfg = &frms->rc_cfg;
MppEncCodecCfg *codec = &cfg->codec;
MppEncH265Cfg *h265 = &codec->h265;
RK_U32 ctu_target_bits_mul_16 = (rc_cfg->bit_target << 4) / frms->mb_per_frame;
RK_U32 ctu_target_bits;
RK_S32 negative_bits_thd, positive_bits_thd;
if (frms->seq_idx == 0 && frms->status.is_intra) {
if (h265->qp_init == -1) {
if (frms->rc_cfg.bit_target) {
ctx->start_qp = cal_first_i_start_qp(frms->rc_cfg.bit_target, frms->mb_per_frame << 4);
ctx->cur_scale_qp = (ctx->start_qp + h265->ip_qp_delta) << 6;
} else {
mpp_log("fix qp case but init qp no set");
h265->qp_init = 26;
ctx->start_qp = 26;
ctx->cur_scale_qp = (ctx->start_qp + h265->ip_qp_delta) << 6;
}
} else {
ctx->start_qp = h265->qp_init;
ctx->cur_scale_qp = (ctx->start_qp + h265->ip_qp_delta) << 6;
}
ctx->cur_scale_qp = mpp_clip(ctx->cur_scale_qp, (h265->min_qp << 6), (h265->max_qp << 6));
ctx->pre_i_qp = ctx->cur_scale_qp >> 6;
ctx->pre_p_qp = ctx->cur_scale_qp >> 6;
} else {
RK_S32 qp_scale = ctx->cur_scale_qp + frms->rc_cfg.next_ratio;
RK_S32 start_qp = 0;
if (frms->status.is_intra) {
qp_scale = mpp_clip(qp_scale, (h265->min_i_qp << 6), (h265->max_i_qp << 6));
start_qp = ((ctx->pre_i_qp + ((qp_scale + frms->rc_cfg.next_i_ratio) >> 6)) >> 1);
start_qp = mpp_clip(start_qp, h265->min_i_qp, h265->max_i_qp);
ctx->pre_i_qp = start_qp;
ctx->start_qp = start_qp;
ctx->cur_scale_qp = qp_scale;
} else {
qp_scale = mpp_clip(qp_scale, (h265->min_qp << 6), (h265->max_qp << 6));
ctx->cur_scale_qp = qp_scale;
ctx->start_qp = qp_scale >> 6;
}
}
if (rc->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
regs->enc_pic.pic_qp = h265->qp_init;
regs->synt_sli1.sli_qp = h265->qp_init;
@ -624,7 +543,6 @@ static MPP_RET vepu541_h265_set_rc_regs(H265eV541HalContext *ctx, H265eV541RegSe
regs->rc_qp.rc_max_qp = h265->qp_init;
regs->rc_qp.rc_min_qp = h265->qp_init;
} else {
RK_S32 rc_max_qp, rc_min_qp;
if (ctu_target_bits_mul_16 >= 0x100000) {
ctu_target_bits_mul_16 = 0x50000;
}
@ -632,26 +550,16 @@ static MPP_RET vepu541_h265_set_rc_regs(H265eV541HalContext *ctx, H265eV541RegSe
negative_bits_thd = 0 - ctu_target_bits / 4;
positive_bits_thd = ctu_target_bits / 4;
if (frms->status.is_intra) {
rc_max_qp = h265->max_i_qp;
rc_min_qp = h265->min_i_qp;
} else {
rc_max_qp = h265->max_qp;
rc_min_qp = h265->min_qp;
}
ctx->start_qp = mpp_clip(ctx->start_qp, rc_min_qp, rc_max_qp);
regs->enc_pic.pic_qp = ctx->start_qp;
regs->synt_sli1.sli_qp = ctx->start_qp;
regs->enc_pic.pic_qp = rc_cfg->quality_target;
regs->synt_sli1.sli_qp = rc_cfg->quality_target;
regs->rc_cfg.rc_en = 1;
regs->rc_cfg.aqmode_en = 1;
regs->rc_cfg.qp_mode = 1;
regs->rc_cfg.rc_ctu_num = frms->mb_wid;
regs->rc_qp.rc_qp_range = h265->raw_dealt_qp;
regs->rc_qp.rc_max_qp = rc_max_qp;
regs->rc_qp.rc_min_qp = rc_min_qp;
regs->rc_qp.rc_max_qp = rc_cfg->quality_max;
regs->rc_qp.rc_min_qp = rc_cfg->quality_min;
regs->rc_tgt.ctu_ebits = ctu_target_bits_mul_16;
regs->rc_erp0.bits_thd0 = negative_bits_thd;
@ -674,8 +582,8 @@ static MPP_RET vepu541_h265_set_rc_regs(H265eV541HalContext *ctx, H265eV541RegSe
regs->rc_adj1.qp_adjust7 = 0;
regs->rc_adj1.qp_adjust8 = 1;
regs->qpmap0.qpmin_area0 = rc_min_qp;
regs->qpmap0.qpmax_area0 = rc_max_qp;
regs->qpmap0.qpmin_area0 = h265->qpmin_map[0];
regs->qpmap0.qpmax_area0 = h265->qpmax_map[0];
regs->qpmap0.qpmin_area1 = h265->qpmin_map[1];
regs->qpmap0.qpmax_area1 = h265->qpmax_map[1];
regs->qpmap0.qpmin_area2 = h265->qpmin_map[2];
@ -949,7 +857,7 @@ MPP_RET hal_h265e_v541_gen_regs(void *hal, HalEncTask *task)
H265eSyntax_new *syn = (H265eSyntax_new *)enc_task->syntax.data;
H265eV541RegSet *regs = NULL;
H265eV541IoctlRegInfo *ioctl_reg_info = NULL;
RcHalCfg *hal_cfg = (RcHalCfg *)ctx->rc_hal_cfg;
EncRcTaskInfo *hal_cfg = (EncRcTaskInfo *)ctx->rc_hal_cfg;
H265eV541IoctlInput *ioctl_info = (H265eV541IoctlInput *)ctx->ioctl_input;
H265eV541RegSet *reg_list = (H265eV541RegSet *)ctx->regs;
MppBuffer mv_info_buf = enc_task->mv_info;
@ -1127,7 +1035,7 @@ MPP_RET hal_h265e_v541_gen_regs(void *hal, HalEncTask *task)
}
vepu541_h265_set_pp_regs(regs, fmt, &ctx->cfg->prep);
vepu541_h265_set_rc_regs(ctx, regs, syn);
vepu541_h265_set_rc_regs(ctx, regs, task);
vepu541_h265_set_slice_regs(syn, regs);
@ -1137,7 +1045,7 @@ MPP_RET hal_h265e_v541_gen_regs(void *hal, HalEncTask *task)
/* ROI configure */
vepu541_h265_set_roi_regs(ctx, regs);
memcpy(&hal_cfg[ctx->frame_cnt_gen_ready], task->hal_ret.data, sizeof(RcHalCfg));
memcpy(&hal_cfg[ctx->frame_cnt_gen_ready], &task->rc_task->info, sizeof(EncRcTaskInfo));
ctx->frame_cnt_gen_ready++;
@ -1248,15 +1156,15 @@ static MPP_RET vepu541_h265_set_feedback(H265eV541HalContext *ctx,
{
RK_U32 k = 0;
H265eV541IoctlOutputElem *elem = NULL;
RcHalCfg *hal_cfg = (RcHalCfg *)ctx->rc_hal_cfg;
EncRcTaskInfo *hal_cfg = (EncRcTaskInfo *)ctx->rc_hal_cfg;
EncRcTaskInfo *hal_rc_ret = (EncRcTaskInfo *)&enc_task->rc_task->info;
vepu541_h265_fbk *fb = &ctx->feedback;
h265e_hal_enter();
MppEncCfgSet *cfg = ctx->cfg;
RK_S32 mb64_num = ((cfg->prep.width + 63) / 64) * ((cfg->prep.height + 63) / 64);
RK_S32 mb8_num = (mb64_num << 6);
RK_S32 mb4_num = (mb8_num << 2);
// RK_S32 mb8_num = (mb64_num << 6);
// RK_S32 mb4_num = (mb8_num << 2);
(void)enc_task;
for (k = 0; k < ctx->num_frames_to_send; k++) {
elem = &out->elem[k];
fb->qp_sum = elem->st_sse_qp.qp_sum;
@ -1313,22 +1221,22 @@ static MPP_RET vepu541_h265_set_feedback(H265eV541HalContext *ctx,
fb->st_lvl4_intra_num = elem->st_lvl4_intra_num;
memcpy(&fb->st_cu_num_qp[0], &elem->st_cu_num_qp[0], sizeof(elem->st_cu_num_qp));
hal_cfg[k].madi = fb->st_madi;
hal_cfg[k].madp = fb->st_madp;
hal_cfg[k].bit_real = fb->out_hw_strm_size * 8;
hal_cfg[k].madi = hal_rc_ret->madi = fb->st_madi;
hal_cfg[k].madp = hal_rc_ret->madp = fb->st_madp;
hal_cfg[k].bit_real = hal_rc_ret->bit_real = fb->out_hw_strm_size * 8;
if (mb64_num > 0) {
hal_cfg[k].intra_lv4_prop = ((fb->st_lvl4_intra_num + (fb->st_lvl8_intra_num << 2) +
/*hal_cfg[k].intra_lv4_prop = ((fb->st_lvl4_intra_num + (fb->st_lvl8_intra_num << 2) +
(fb->st_lvl16_intra_num << 4) +
(fb->st_lvl32_intra_num << 6)) << 8) / mb4_num;
hal_cfg[k].inter_lv8_prop = ((fb->st_lvl8_inter_num + (fb->st_lvl16_inter_num << 2) +
(fb->st_lvl32_inter_num << 4) +
(fb->st_lvl64_inter_num << 6)) << 8) / mb8_num;
(fb->st_lvl64_inter_num << 6)) << 8) / mb8_num;*/
hal_cfg[k].quality_real = (fb->qp_sum << 6) / mb64_num;
hal_cfg[k].sse = fb->sse_sum / mb64_num;
hal_cfg[k].quality_real = fb->qp_sum / mb64_num;
hal_rc_ret->bit_real = hal_cfg[k].quality_real;
// hal_cfg[k].sse = fb->sse_sum / mb64_num;
}
}
@ -1408,7 +1316,7 @@ MPP_RET hal_h265e_v541_get_task(void *hal, HalEncTask *task)
H265eSyntax_new *syn = (H265eSyntax_new *)task->syntax.data;
MppFrame frame = task->frame;
MppMeta meta = mpp_frame_get_meta(frame);
H265eFrmInfo *frms = &syn->frms;
EncFrmStatus *frm_status = &task->rc_task->frm;
h265e_hal_enter();
if ((!ctx->alloc_flg)) {
@ -1421,7 +1329,7 @@ MPP_RET hal_h265e_v541_get_task(void *hal, HalEncTask *task)
ctx->alloc_flg = 1;
}
ctx->last_frame_type = ctx->frame_type;
if (frms->status.is_intra) {
if (frm_status->is_intra) {
ctx->frame_type = INTRA_FRAME;
} else {
ctx->frame_type = INTER_P_FRAME;

View file

@ -63,16 +63,12 @@ typedef struct HalH264eVepu2Ctx_t {
H264eFrmInfo *frms;
H264eReorderInfo *reorder;
H264eMarkingInfo *marking;
RcSyntax *rc_syn;
/* special TSVC stream header fixup */
size_t buf_size;
RK_U8 *src_buf;
RK_U8 *dst_buf;
/* syntax for output to enc_impl */
RcHalCfg hal_rc_cfg;
/* vepu2 macroblock ratecontrol context */
HalH264eVepuMbRcCtx rc_ctx;
@ -183,7 +179,6 @@ static RK_U32 update_vepu2_syntax(HalH264eVepu2Ctx *ctx, MppSyntax *syntax)
} break;
case H264E_SYN_RC : {
hal_h264e_dbg_detail("update rc");
ctx->rc_syn = desc->p;
} break;
case H264E_SYN_ROI :
case H264E_SYN_OSD :
@ -229,7 +224,6 @@ static MPP_RET hal_h264e_vepu2_get_task_v2(void *hal, HalEncTask *task)
MppBuffer recn = h264e_vepu_buf_get_frame_buffer(hw_bufs, frms->curr_idx);
MppBuffer refr = h264e_vepu_buf_get_frame_buffer(hw_bufs, frms->refr_idx);
EncFrmStatus info = frms->status;
size_t yuv_size = hw_bufs->yuv_size;
hw_addr->recn[0] = mpp_buffer_get_fd(recn);
@ -237,12 +231,6 @@ static MPP_RET hal_h264e_vepu2_get_task_v2(void *hal, HalEncTask *task)
hw_addr->recn[1] = hw_addr->recn[0] + (yuv_size << 10);
hw_addr->refr[1] = hw_addr->refr[0] + (yuv_size << 10);
// update input rc cfg
ctx->hal_rc_cfg = frms->rc_cfg;
// prepare mb rc config
h264e_vepu_mbrc_prepare(ctx->rc_ctx, ctx->rc_syn, &info, &ctx->hw_mbrc);
hal_h264e_dbg_func("leave %p\n", hal);
return MPP_OK;
@ -289,6 +277,8 @@ static MPP_RET hal_h264e_vepu2_gen_regs_v2(void *hal, HalEncTask *task)
HalH264eVepuPrep *hw_prep = &ctx->hw_prep;
HalH264eVepuAddr *hw_addr = &ctx->hw_addr;
HalH264eVepuMbRc *hw_mbrc = &ctx->hw_mbrc;
EncRcTaskInfo *rc_info = &task->rc_task->info;
EncFrmStatus *frm = &task->rc_task->frm;
SynH264eSps *sps = ctx->sps;
SynH264ePps *pps = ctx->pps;
H264eSlice *slice = ctx->slice;
@ -300,14 +290,19 @@ static MPP_RET hal_h264e_vepu2_gen_regs_v2(void *hal, HalEncTask *task)
RK_U32 val = 0;
RK_S32 i = 0;
// TODO: Fix QP here for debug
hw_mbrc->qp_init = 26;
hw_mbrc->qp_max = 26;
hw_mbrc->qp_min = 26;
hw_mbrc->qp_init = rc_info->quality_target;
hw_mbrc->qp_max = rc_info->quality_max;
hw_mbrc->qp_min = rc_info->quality_min;
hal_h264e_dbg_rc("qp [%d : %d : %d]\n", rc_info->quality_min,
rc_info->quality_target, rc_info->quality_max);
hal_h264e_dbg_func("enter %p\n", hal);
hal_h264e_dbg_detail("frame %d generate regs now", ctx->frms->seq_idx);
hal_h264e_dbg_detail("frame %d generate regs now", frm->seq_idx);
// prepare mb rc config
h264e_vepu_mbrc_prepare(ctx->rc_ctx, &ctx->hw_mbrc, task->rc_task, ctx->cfg);
/* setup output address with offset */
first_free_bit = setup_output_packet(reg, task->output, offset);
@ -800,6 +795,7 @@ static MPP_RET hal_h264e_vepu2_wait_v2(void *hal, HalEncTask *task)
static MPP_RET hal_h264e_vepu2_ret_task_v2(void *hal, HalEncTask *task)
{
HalH264eVepu2Ctx *ctx = (HalH264eVepu2Ctx *)hal;
EncRcTaskInfo *rc_info = &task->rc_task->info;
RK_U32 mb_w = ctx->sps->pic_width_in_mbs;
RK_U32 mb_h = ctx->sps->pic_height_in_mbs;
RK_U32 mbs = mb_w * mb_h;
@ -808,10 +804,12 @@ static MPP_RET hal_h264e_vepu2_ret_task_v2(void *hal, HalEncTask *task)
task->length += ctx->hw_mbrc.out_strm_size;
ctx->hal_rc_cfg.bit_real = task->length;
ctx->hal_rc_cfg.quality_real = ctx->hw_mbrc.qp_sum / mbs;
rc_info->bit_real = task->length * 8;
rc_info->quality_real = ctx->hw_mbrc.qp_sum / mbs;
task->hal_ret.data = &ctx->hal_rc_cfg;
hal_h264e_dbg_rc("real bit %d quality %d\n", rc_info->bit_real, rc_info->quality_real);
task->hal_ret.data = rc_info;
task->hal_ret.number = 1;
hal_h264e_dbg_func("leave %p\n", hal);

View file

@ -65,6 +65,9 @@ typedef struct HalH264eVepuMbRcImpl_t {
/* estimated first I frame qp */
RK_S32 qp_init_est;
RK_S32 frame_type;
RK_S32 pre_frame_type;
} HalH264eVepuMbRcImpl;
static void vepu_swap_endian(RK_U32 *buf, RK_S32 size_bytes)
@ -506,18 +509,9 @@ MPP_RET h264e_vepu_mbrc_deinit(HalH264eVepuMbRcCtx ctx)
return MPP_OK;
}
static RK_S32 qp_tbl[2][13] = {
{
26, 36, 48, 63, 85, 110, 152, 208, 313, 427, 936,
1472, 0x7fffffff
},
{42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6}
};
MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet*cfg)
{
HalH264eVepuMbRcImpl *p = (HalH264eVepuMbRcImpl *)ctx;
MppEncH264Cfg *codec = &cfg->codec.h264;
MppEncPrepCfg *prep = &cfg->prep;
MppEncRcCfg *rc = &cfg->rc;
@ -550,25 +544,6 @@ MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet*cfg)
// if not constant
p->mb_bit_rc_enable = rc->rc_mode != MPP_ENC_RC_MODE_FIXQP;
// init first frame QP
if (p->bits_per_pic > 1000000)
p->qp_init_est = codec->qp_min;
else {
RK_S32 upscale = 8000;
RK_S32 i = -1;
RK_S32 bits_per_pic = p->bits_per_pic;
RK_S32 mbs = p->mbs;
bits_per_pic >>= 5;
bits_per_pic *= mbs + 250;
bits_per_pic /= 350 + (3 * mbs) / 4;
bits_per_pic = axb_div_c(bits_per_pic, upscale, mbs << 6);
while (qp_tbl[0][++i] < bits_per_pic);
p->qp_init_est = qp_tbl[1][i];
}
hal_h264e_dbg_rc("estimated init qp %d\n", p->qp_init_est);
// init first frame mad parameter
@ -584,49 +559,113 @@ MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet*cfg)
p->check_point_distance = 0;
}
p->frame_type = INTRA_FRAME;
p->pre_frame_type = INTRA_FRAME;
hal_h264e_dbg_rc("leave\n");
return MPP_OK;
}
MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, RcSyntax *rc,
EncFrmStatus *info, HalH264eVepuMbRc *mbrc)
#define WORD_CNT_MAX 65535
MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc,
EncRcTask *rc_task, MppEncCfgSet *cfg)
{
HalH264eVepuMbRcImpl *p = (HalH264eVepuMbRcImpl *)ctx;
RK_S32 target_bits = rc->bit_target;
RK_S32 target_step = target_bits / (p->check_point_count + 1);
RK_S32 target_sum = 0;
RK_S32 tmp;
EncFrmStatus *frm = &rc_task->frm;
EncRcTaskInfo *info = &rc_task->info;
MppEncH264Cfg *codec = &cfg->codec.h264;
RK_S32 i;
const RK_S32 sscale = 256;
RK_S32 scaler, srcPrm;
RK_S32 tmp, nonZeroTarget;
RK_S32 coeffCntMax = p->mbs * 24 * 16;
mpp_assert(target_step >= 0);
(void) info;
if (!p->mb_bit_rc_enable) {
if (codec->qp_init == -1) {
mpp_log("fix qp case but qp no set default qp = 26");
mbrc->qp_init = 26;
} else {
mbrc->qp_init = codec->qp_init;
}
for (i = 0; i < VEPU_CHECK_POINTS_MAX; i++) {
target_sum += target_step;
mbrc->cp_target[i] = mpp_clip(target_sum / 32, -32768, 32767);
mbrc->qp_min = mbrc->qp_init;
mbrc->qp_max = mbrc->qp_init;
return MPP_OK;
}
tmp = target_step / 8;
p->pre_frame_type = p->frame_type;
p->frame_type = (frm->is_intra) ? INTRA_FRAME : INTER_P_FRAME;
mbrc->qp_init = info->quality_target;
mbrc->qp_min = codec->qp_min;
mbrc->qp_max = codec->qp_max;
if (mbrc->rlc_count == 0) {
mbrc->rlc_count = 1;
}
srcPrm = axb_div_c(mbrc->out_strm_size * 8, 256, mbrc->rlc_count);
/* Disable Mb Rc for Intra Slices, because coeffTarget will be wrong */
if (frm->is_intra || srcPrm == 0)
return 0;
/* Required zero cnt */
nonZeroTarget = axb_div_c(info->bit_target, 256, srcPrm);
nonZeroTarget = MPP_MIN(coeffCntMax, MPP_MAX(0, nonZeroTarget));
nonZeroTarget = MPP_MIN(0x7FFFFFFFU / 1024U, (RK_U32)nonZeroTarget);
if (nonZeroTarget > 0) {
scaler = axb_div_c(nonZeroTarget, sscale, (RK_S32) p->mbs);
} else {
return 0;
}
if ((p->frame_type != p->pre_frame_type) || (mbrc->rlc_count == 0)) {
for (i = 0; i < VEPU_CHECK_POINTS_MAX; i++) {
tmp = (scaler * (p->check_point_distance * (i + 1) + 1)) / sscale;
tmp = MPP_MIN(WORD_CNT_MAX, tmp / 32 + 1);
if (tmp < 0) tmp = WORD_CNT_MAX; /* Detect overflow */
mbrc->cp_target[i] = tmp; /* div32 for regs */
}
tmp = axb_div_c(p->bits_per_pic, 256, srcPrm);
} else {
for (i = 0; i < VEPU_CHECK_POINTS_MAX; i++) {
tmp = (RK_S32) (mbrc->cp_usage[i] * scaler) / sscale;
tmp = MPP_MIN(WORD_CNT_MAX, tmp / 32 + 1);
if (tmp < 0) tmp = WORD_CNT_MAX; /* Detect overflow */
mbrc->cp_target[i] = tmp; /* div32 for regs */
}
tmp = axb_div_c(p->bits_per_pic, 256, srcPrm);
}
mbrc->cp_error[0] = -tmp * 3;
mbrc->cp_delta_qp[0] = -3;
mbrc->cp_delta_qp[0] = 3;
mbrc->cp_error[1] = -tmp * 2;
mbrc->cp_delta_qp[1] = -2;
mbrc->cp_delta_qp[1] = 2;
mbrc->cp_error[2] = -tmp * 1;
mbrc->cp_delta_qp[2] = -1;
mbrc->cp_delta_qp[2] = 1;
mbrc->cp_error[3] = tmp * 1;
mbrc->cp_delta_qp[3] = 0;
mbrc->cp_error[4] = tmp * 2;
mbrc->cp_delta_qp[4] = 1;
mbrc->cp_delta_qp[4] = -1;
mbrc->cp_error[5] = tmp * 3;
mbrc->cp_delta_qp[5] = 2;
mbrc->cp_delta_qp[5] = -2;
mbrc->cp_error[6] = tmp * 4;
mbrc->cp_delta_qp[6] = 3;
mbrc->cp_delta_qp[6] = -3;
for (i = 0; i < CTRL_LEVELS; i++) {
tmp = mbrc->cp_error[i];
tmp = mpp_clip(tmp / 4, -32768, 32767);
mbrc->cp_error[i] = tmp;
}
mbrc->mad_qp_change = 2;
mbrc->mad_threshold = 2;
mbrc->cp_distance_mbs = p->check_point_distance;
return MPP_OK;
}

View file

@ -184,8 +184,8 @@ MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet *cfg);
*
* Then output the HalH264eVepuMbRc for register generation
*/
MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, RcSyntax *rc,
EncFrmStatus *info, HalH264eVepuMbRc *mbrc);
MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc,
EncRcTask *rc_task, MppEncCfgSet *cfg);
MPP_RET h264e_vepu_mbrc_update(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc);
#ifdef __cplusplus