mirror of
https://github.com/nyanmisaka/mpp.git
synced 2025-10-06 01:26:49 +08:00
[mpp_enc_ref]: Add MppEncRef/MppEncRefs module
Add MppEncRef/MppEncRefs module MppEncRefs is for mpp encoder coded picture buffer (CPB) management. MppEncRefs will gnerate reference buffer status EncCpbStatus for each encoder to implement its own process. Change-Id: I5f85a0f46dc6bc40954b0393ba52ad4008565643 Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
This commit is contained in:
@@ -17,7 +17,9 @@
|
|||||||
#ifndef __MPP_RC_DEFS_H__
|
#ifndef __MPP_RC_DEFS_H__
|
||||||
#define __MPP_RC_DEFS_H__
|
#define __MPP_RC_DEFS_H__
|
||||||
|
|
||||||
#include "rk_type.h"
|
#include "rk_venc_ref.h"
|
||||||
|
|
||||||
|
#define MAX_CPB_REFS (8)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EncFrmStatus controls record the encoding frame status and also control
|
* EncFrmStatus controls record the encoding frame status and also control
|
||||||
@@ -29,86 +31,106 @@
|
|||||||
* 16 ~ 31 reference frame status
|
* 16 ~ 31 reference frame status
|
||||||
* bit 32 ~ 63 encoding flow control
|
* bit 32 ~ 63 encoding flow control
|
||||||
*/
|
*/
|
||||||
typedef struct EncFrmStatus_t {
|
typedef union EncFrmStatus_u {
|
||||||
/*
|
struct {
|
||||||
* bit 0 ~ 31 frame status
|
/*
|
||||||
*/
|
* bit 0 ~ 31 frame status
|
||||||
/*
|
*/
|
||||||
* 0 - inter frame
|
/* status flag */
|
||||||
* 1 - intra frame
|
RK_U32 valid : 1;
|
||||||
*/
|
RK_U32 reserved0 : 3;
|
||||||
RK_U32 is_intra : 1;
|
|
||||||
|
|
||||||
/*
|
/* reference status flag */
|
||||||
* Valid when is_intra is true
|
/*
|
||||||
* 0 - normal intra frame
|
* 0 - inter frame
|
||||||
* 1 - IDR frame
|
* 1 - intra frame
|
||||||
*/
|
*/
|
||||||
RK_U32 is_idr : 1;
|
RK_U32 is_intra : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 - mark as reference frame
|
* Valid when is_intra is true
|
||||||
* 1 - mark as non-refernce frame
|
* 0 - normal intra frame
|
||||||
*/
|
* 1 - IDR frame
|
||||||
RK_U32 is_non_ref : 1;
|
*/
|
||||||
|
RK_U32 is_idr : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Valid when is_non_ref is false
|
* 0 - mark as reference frame
|
||||||
* 0 - mark as short-term reference frame
|
* 1 - mark as non-refernce frame
|
||||||
* 1 - mark as long-term refernce frame
|
*/
|
||||||
*/
|
RK_U32 is_non_ref : 1;
|
||||||
RK_U32 is_lt_ref : 1;
|
|
||||||
|
|
||||||
RK_U32 reserved0 : 4;
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
/* bit 8 - 15 */
|
/* bit 8 - 15 */
|
||||||
RK_U32 lt_idx : 4;
|
RK_U32 lt_idx : 4;
|
||||||
RK_U32 temporal_id : 4;
|
RK_U32 temporal_id : 4;
|
||||||
|
|
||||||
/* distance between current frame and reference frame */
|
/* distance between current frame and reference frame */
|
||||||
RK_S32 ref_dist : 16;
|
MppEncRefMode ref_mode : 6;
|
||||||
|
RK_S32 ref_arg : 8;
|
||||||
|
RK_S32 ref_dist : 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bit 32 ~ 63 encoder flow control flags
|
* bit 32 ~ 63 encoder flow control flags
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* 0 - normal frame encoding
|
* 0 - normal frame encoding
|
||||||
* 1 - current frame will be dropped
|
* 1 - current frame will be dropped
|
||||||
*/
|
*/
|
||||||
RK_U32 drop : 1;
|
RK_U32 drop : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 - rate control module does not change frame type parameter
|
* 0 - rate control module does not change frame type parameter
|
||||||
* 1 - rate control module changes frame type parameter reencode is needed
|
* 1 - rate control module changes frame type parameter reencode is needed
|
||||||
* to reprocess the dpb process. Also this means dpb module will follow
|
* to reprocess the dpb process. Also this means dpb module will follow
|
||||||
* the frame status parameter provided by rate control module.
|
* the frame status parameter provided by rate control module.
|
||||||
*/
|
*/
|
||||||
RK_U32 re_dpb_proc : 1;
|
RK_U32 re_dpb_proc : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 - current frame encoding is in normal flow
|
* 0 - current frame encoding is in normal flow
|
||||||
* 1 - current frame encoding is in reencode flow
|
* 1 - current frame encoding is in reencode flow
|
||||||
*/
|
*/
|
||||||
RK_U32 reencode : 1;
|
RK_U32 reencode : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When true current frame size is super large then the frame should be reencoded.
|
* When true current frame size is super large then the frame should be reencoded.
|
||||||
*/
|
*/
|
||||||
RK_U32 super_frame : 1;
|
RK_U32 super_frame : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When true currnet frame is force to encoded as software skip frame
|
* When true currnet frame is force to encoded as software skip frame
|
||||||
*/
|
*/
|
||||||
RK_U32 force_pskip : 1;
|
RK_U32 force_pskip : 1;
|
||||||
RK_U32 reserved1 : 3;
|
RK_U32 reserved1 : 3;
|
||||||
|
|
||||||
/* reencode times */
|
/* reencode times */
|
||||||
RK_U32 reencode_times : 8;
|
RK_U32 reencode_times : 8;
|
||||||
|
|
||||||
/* sequential index for each frame */
|
/* sequential index for each frame */
|
||||||
RK_U32 seq_idx : 16;
|
RK_U32 seq_idx : 16;
|
||||||
|
};
|
||||||
|
RK_U64 val;
|
||||||
} EncFrmStatus;
|
} EncFrmStatus;
|
||||||
|
|
||||||
|
typedef struct EncCpbStatus_t {
|
||||||
|
RK_S32 seq_idx;
|
||||||
|
|
||||||
|
EncFrmStatus curr;
|
||||||
|
EncFrmStatus refr;
|
||||||
|
|
||||||
|
/* initial cpb status for current frame encoding */
|
||||||
|
EncFrmStatus init[MAX_CPB_REFS];
|
||||||
|
/* final cpb status after current frame encoding */
|
||||||
|
EncFrmStatus final[MAX_CPB_REFS];
|
||||||
|
} EncCpbStatus;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* communication channel between rc / hal / hardware
|
* communication channel between rc / hal / hardware
|
||||||
*
|
*
|
||||||
@@ -136,6 +158,7 @@ typedef struct EncRcCommonInfo_t {
|
|||||||
} EncRcTaskInfo;
|
} EncRcTaskInfo;
|
||||||
|
|
||||||
typedef struct EncRcTask_s {
|
typedef struct EncRcTask_s {
|
||||||
|
EncCpbStatus cpb;
|
||||||
EncFrmStatus frm;
|
EncFrmStatus frm;
|
||||||
EncRcTaskInfo info;
|
EncRcTaskInfo info;
|
||||||
MppFrame frame;
|
MppFrame frame;
|
||||||
|
@@ -4,6 +4,8 @@
|
|||||||
# add mpp basic components
|
# add mpp basic components
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
add_library(mpp_base STATIC
|
add_library(mpp_base STATIC
|
||||||
|
mpp_enc_refs.cpp
|
||||||
|
mpp_enc_ref.cpp
|
||||||
mpp_enc_cfg.cpp
|
mpp_enc_cfg.cpp
|
||||||
mpp_buf_slot.cpp
|
mpp_buf_slot.cpp
|
||||||
mpp_buffer_impl.cpp
|
mpp_buffer_impl.cpp
|
||||||
|
69
mpp/base/inc/mpp_enc_ref.h
Normal file
69
mpp/base/inc/mpp_enc_ref.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MPP_ENC_REF_H__
|
||||||
|
#define __MPP_ENC_REF_H__
|
||||||
|
|
||||||
|
#include "rk_venc_ref.h"
|
||||||
|
|
||||||
|
#define REF_MODE_IS_GLOBAL(mode) ((mode >= REF_MODE_GLOBAL) && (mode < REF_MODE_GLOBAL_BUTT))
|
||||||
|
#define REF_MODE_IS_LT_MODE(mode) ((mode > REF_MODE_LT) && (mode < REF_MODE_LT_BUTT))
|
||||||
|
#define REF_MODE_IS_ST_MODE(mode) ((mode > REF_MODE_ST) && (mode < REF_MODE_ST_BUTT))
|
||||||
|
|
||||||
|
typedef struct MppEncCpbInfo_t {
|
||||||
|
RK_S32 dpb_size;
|
||||||
|
RK_S32 max_lt_cnt;
|
||||||
|
RK_S32 max_st_cnt;
|
||||||
|
RK_S32 max_lt_idx;
|
||||||
|
RK_S32 max_st_tid;
|
||||||
|
/* loop length of st/lt config */
|
||||||
|
RK_S32 lt_gop;
|
||||||
|
RK_S32 st_gop;
|
||||||
|
} MppEncCpbInfo;
|
||||||
|
|
||||||
|
typedef struct MppEncRefCfgImpl_t {
|
||||||
|
const char *name;
|
||||||
|
RK_S32 ready;
|
||||||
|
RK_U32 debug;
|
||||||
|
|
||||||
|
/* config from user */
|
||||||
|
RK_S32 max_lt_cfg;
|
||||||
|
RK_S32 max_st_cfg;
|
||||||
|
RK_S32 lt_cfg_cnt;
|
||||||
|
RK_S32 st_cfg_cnt;
|
||||||
|
MppEncRefLtFrmCfg *lt_cfg;
|
||||||
|
MppEncRefStFrmCfg *st_cfg;
|
||||||
|
|
||||||
|
/* generated parameter for MppEncRefs */
|
||||||
|
MppEncCpbInfo cpb_info;
|
||||||
|
} MppEncRefCfgImpl;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MppEncRefCfg mpp_enc_ref_default(void);
|
||||||
|
MPP_RET mpp_enc_ref_cfg_copy(MppEncRefCfg dst, MppEncRefCfg src);
|
||||||
|
MppEncCpbInfo *mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref);
|
||||||
|
|
||||||
|
#define check_is_mpp_enc_ref_cfg(ref) _check_is_mpp_enc_ref_cfg(__FUNCTION__, ref)
|
||||||
|
MPP_RET _check_is_mpp_enc_ref_cfg(const char *func, void *ref);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__MPP_ENC_REF_H__*/
|
78
mpp/base/inc/mpp_enc_refs.h
Normal file
78
mpp/base/inc/mpp_enc_refs.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MPP_ENC_REFS_H__
|
||||||
|
#define __MPP_ENC_REFS_H__
|
||||||
|
|
||||||
|
#include "mpp_enc_cfg.h"
|
||||||
|
#include "mpp_enc_ref.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MppEncRefs has two runtime mode:
|
||||||
|
*
|
||||||
|
* 1. dryrun mode
|
||||||
|
* This mode is for estimating the dpb size and configure check.
|
||||||
|
*
|
||||||
|
* 2. runtime mode
|
||||||
|
* Thie mode is for real dpb loop in real encoder workflow.
|
||||||
|
*
|
||||||
|
* When encoder is running user can change the frame property by MppEncRefFrmUsrCfg.
|
||||||
|
*/
|
||||||
|
#define ENC_FORCE_IDR (0x00000001)
|
||||||
|
#define ENC_FORCE_LT_REF_IDX (0x00000002)
|
||||||
|
#define ENC_FORCE_TEMPORAL_ID (0x00000004)
|
||||||
|
#define ENC_FORCE_REF_MODE (0x00000008)
|
||||||
|
|
||||||
|
typedef struct MppEncRefFrmForceCfg_t {
|
||||||
|
RK_U32 force_flag;
|
||||||
|
RK_S32 force_idr;
|
||||||
|
RK_S32 force_lt_idx;
|
||||||
|
RK_S32 force_temporal_id;
|
||||||
|
MppEncRefMode force_ref_mode;
|
||||||
|
RK_S32 force_ref_arg;
|
||||||
|
} MppEncRefFrmUsrCfg;
|
||||||
|
|
||||||
|
typedef void* MppEncRefs;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_init(MppEncRefs *refs, MppEncCfgSet *cfg);
|
||||||
|
MPP_RET mpp_enc_refs_deinit(MppEncRefs *refs);
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_set_cfg(MppEncRefs refs, MppEncRefCfg ref_cfg);
|
||||||
|
MPP_RET mpp_enc_refs_set_usr_cfg(MppEncRefs refs, MppEncRefFrmUsrCfg *force);
|
||||||
|
|
||||||
|
/* get dpb size */
|
||||||
|
MPP_RET mpp_enc_refs_get_cpb_info(MppEncRefs refs, MppEncCpbInfo *info);
|
||||||
|
/* get status for next frame */
|
||||||
|
MPP_RET mpp_enc_refs_get_cpb(MppEncRefs refs, EncCpbStatus *status);
|
||||||
|
/* dryrun and check all configure */
|
||||||
|
MPP_RET mpp_enc_refs_dryrun(MppEncRefs refs);
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_stash(MppEncRefs refs);
|
||||||
|
MPP_RET mpp_enc_refs_rollback(MppEncRefs refs);
|
||||||
|
|
||||||
|
#define dump_frm(frm) _dump_frm(frm, __FUNCTION__, __LINE__)
|
||||||
|
|
||||||
|
void _dump_frm(EncFrmStatus *frm, const char *func, RK_S32 line);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__MPP_ENC_REFS_H__*/
|
427
mpp/base/mpp_enc_ref.cpp
Normal file
427
mpp/base/mpp_enc_ref.cpp
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
/*
|
||||||
|
* 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_enc_ref"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mpp_env.h"
|
||||||
|
#include "mpp_log.h"
|
||||||
|
#include "mpp_mem.h"
|
||||||
|
#include "mpp_time.h"
|
||||||
|
|
||||||
|
#include "mpp_rc_defs.h"
|
||||||
|
#include "mpp_enc_ref.h"
|
||||||
|
#include "mpp_enc_refs.h"
|
||||||
|
|
||||||
|
#define setup_mpp_enc_ref_cfg(ref) \
|
||||||
|
((MppEncRefCfgImpl*)ref)->name = module_name;
|
||||||
|
|
||||||
|
static const char *module_name = MODULE_TAG;
|
||||||
|
|
||||||
|
MPP_RET _check_is_mpp_enc_ref_cfg(const char *func, void *ref)
|
||||||
|
{
|
||||||
|
if (NULL == ref) {
|
||||||
|
mpp_err("%s input ref check NULL failed\n", func);
|
||||||
|
return MPP_NOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((MppEncRefCfgImpl*)(ref))->name != module_name) {
|
||||||
|
mpp_err("%s input ref check %p %p failed\n", func, ((MppEncRefCfgImpl*)(ref))->name);
|
||||||
|
return MPP_NOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_init(MppEncRefCfg *ref)
|
||||||
|
{
|
||||||
|
if (NULL == ref) {
|
||||||
|
mpp_err_f("invalid NULL input ref_cfg\n");
|
||||||
|
return MPP_ERR_NULL_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = mpp_calloc(MppEncRefCfgImpl, 1);
|
||||||
|
*ref = p;
|
||||||
|
if (NULL == p) {
|
||||||
|
mpp_err_f("malloc failed\n");
|
||||||
|
return MPP_ERR_NULL_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpp_env_get_u32("enc_ref_cfg_debug", &p->debug, 0);
|
||||||
|
|
||||||
|
setup_mpp_enc_ref_cfg(p);
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_deinit(MppEncRefCfg *ref)
|
||||||
|
{
|
||||||
|
if (!ref || check_is_mpp_enc_ref_cfg(*ref)) {
|
||||||
|
mpp_err_f("input %p check failed\n", ref);
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)(*ref);
|
||||||
|
MPP_FREE(p->lt_cfg);
|
||||||
|
MPP_FREE(p->st_cfg);
|
||||||
|
MPP_FREE(p);
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_reset(MppEncRefCfg ref)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref))
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
|
||||||
|
MPP_FREE(p->lt_cfg);
|
||||||
|
MPP_FREE(p->st_cfg);
|
||||||
|
memset(p, 0, sizeof(*p));
|
||||||
|
setup_mpp_enc_ref_cfg(p);
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_set_cfg_cnt(MppEncRefCfg ref, RK_S32 lt_cnt, RK_S32 st_cnt)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref))
|
||||||
|
return MPP_ERR_NULL_PTR;
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
|
||||||
|
MppEncRefLtFrmCfg *lt_cfg = p->lt_cfg;
|
||||||
|
MppEncRefStFrmCfg *st_cfg = p->st_cfg;;
|
||||||
|
|
||||||
|
if (lt_cfg || st_cfg) {
|
||||||
|
mpp_err_f("do call reset before setup new cnout\n");
|
||||||
|
MPP_FREE(lt_cfg);
|
||||||
|
MPP_FREE(st_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lt_cnt) {
|
||||||
|
lt_cfg = mpp_calloc(MppEncRefLtFrmCfg, lt_cnt);
|
||||||
|
if (NULL == lt_cfg)
|
||||||
|
mpp_log_f("failed to create %d lt ref cfg\n", lt_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st_cnt) {
|
||||||
|
st_cfg = mpp_calloc(MppEncRefStFrmCfg, st_cnt);
|
||||||
|
if (NULL == st_cfg)
|
||||||
|
mpp_log_f("failed to create %d st ref cfg\n", lt_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->max_lt_cfg = lt_cnt;
|
||||||
|
p->max_st_cfg = st_cnt;
|
||||||
|
p->lt_cfg_cnt = 0;
|
||||||
|
p->st_cfg_cnt = 0;
|
||||||
|
p->lt_cfg = lt_cfg;
|
||||||
|
p->st_cfg = st_cfg;
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_add_lt_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefLtFrmCfg *frm)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref))
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
|
||||||
|
|
||||||
|
if (p->debug)
|
||||||
|
mpp_log("ref %p add lt %d cfg idx %d tid %d gap %d delay %d ref mode %x\n",
|
||||||
|
ref, p->lt_cfg_cnt, frm->lt_idx, frm->temporal_id,
|
||||||
|
frm->lt_gap, frm->lt_delay, frm->ref_mode);
|
||||||
|
|
||||||
|
memcpy(&p->lt_cfg[p->lt_cfg_cnt], frm, sizeof(*frm) * cnt);
|
||||||
|
p->lt_cfg_cnt += cnt;
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_add_st_cfg(MppEncRefCfg ref, RK_S32 cnt, MppEncRefStFrmCfg *frm)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref)) {
|
||||||
|
mpp_err_f("input %p check failed\n", ref);
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
|
||||||
|
|
||||||
|
if (p->debug)
|
||||||
|
mpp_log("ref %p add lt %d cfg non %d tid %d gap repeat %d ref mode %x arg %d\n",
|
||||||
|
ref, p->st_cfg_cnt, frm->is_non_ref, frm->temporal_id,
|
||||||
|
frm->repeat, frm->ref_mode, frm->ref_arg);
|
||||||
|
|
||||||
|
memcpy(&p->st_cfg[p->st_cfg_cnt], frm, sizeof(*frm) * cnt);
|
||||||
|
p->st_cfg_cnt += cnt;
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_check(MppEncRefCfg ref)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref))
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
|
||||||
|
RK_S32 lt_cfg_cnt = p->lt_cfg_cnt;
|
||||||
|
RK_S32 st_cfg_cnt = p->st_cfg_cnt;
|
||||||
|
RK_S32 max_lt_ref_cnt = 0;
|
||||||
|
RK_S32 max_lt_ref_idx = 0;
|
||||||
|
RK_S32 lt_idx_used_mask = 0;
|
||||||
|
RK_S32 lt_dryrun_length = 0;
|
||||||
|
RK_S32 max_st_ref_cnt = 0;
|
||||||
|
RK_S32 max_st_tid = 0;
|
||||||
|
RK_S32 st_tid_used_mask = 0;
|
||||||
|
RK_S32 st_dryrun_length = 0;
|
||||||
|
RK_S32 ready = 1;
|
||||||
|
|
||||||
|
/* parse and check gop config for encoder */
|
||||||
|
if (lt_cfg_cnt) {
|
||||||
|
RK_S32 pos = 0;
|
||||||
|
MppEncRefLtFrmCfg *cfg = p->lt_cfg;
|
||||||
|
|
||||||
|
for (pos = 0; pos < lt_cfg_cnt; pos++, cfg++) {
|
||||||
|
MppEncRefMode ref_mode = cfg->ref_mode;
|
||||||
|
RK_S32 temporal_id = cfg->temporal_id;
|
||||||
|
RK_S32 lt_idx = cfg->lt_idx;
|
||||||
|
RK_U32 lt_idx_mask = 1 << lt_idx;
|
||||||
|
|
||||||
|
/* check lt idx */
|
||||||
|
if (lt_idx >= MPP_ENC_MAX_LT_REF_NUM) {
|
||||||
|
mpp_err_f("ref cfg %p lt cfg %d with invalid lt_idx %d larger than MPP_ENC_MAX_LT_REF_NUM\n",
|
||||||
|
ref, pos, lt_idx);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lt_idx_used_mask & lt_idx_mask) {
|
||||||
|
mpp_err_f("ref cfg %p lt cfg %d with redefined lt_idx %d config\n",
|
||||||
|
ref, pos, lt_idx);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(lt_idx_used_mask & lt_idx_mask)) {
|
||||||
|
lt_idx_used_mask |= lt_idx_mask;
|
||||||
|
max_lt_ref_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lt_idx > max_lt_ref_idx)
|
||||||
|
max_lt_ref_idx = lt_idx;
|
||||||
|
|
||||||
|
/* check temporal id */
|
||||||
|
if (temporal_id != 0) {
|
||||||
|
mpp_err_f("ref cfg %p lt cfg %d with invalid temporal_id %d is non-zero\n",
|
||||||
|
ref, pos, temporal_id);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check gop mode */
|
||||||
|
if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_LT_MODE(ref_mode)) {
|
||||||
|
mpp_err_f("ref cfg %p lt cfg %d with invalid ref mode %x\n",
|
||||||
|
ref, pos, ref_mode);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if check failed just quit */
|
||||||
|
if (!ready)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (cfg->lt_gap && (cfg->lt_gap + cfg->lt_delay > lt_dryrun_length))
|
||||||
|
lt_dryrun_length = cfg->lt_gap + cfg->lt_delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check st-ref config */
|
||||||
|
if (ready && st_cfg_cnt) {
|
||||||
|
RK_S32 pos = 0;
|
||||||
|
MppEncRefStFrmCfg *cfg = p->st_cfg;
|
||||||
|
|
||||||
|
for (pos = 0; pos < st_cfg_cnt; pos++, cfg++) {
|
||||||
|
MppEncRefMode ref_mode = cfg->ref_mode;
|
||||||
|
RK_S32 temporal_id = cfg->temporal_id;
|
||||||
|
RK_U32 tid_mask = 1 << temporal_id;
|
||||||
|
|
||||||
|
/* check temporal_id */
|
||||||
|
if (temporal_id > MPP_ENC_MAX_TEMPORAL_LAYER_NUM - 1) {
|
||||||
|
mpp_err_f("ref cfg %p st cfg %d with invalid temporal_id %d larger than MPP_ENC_MAX_TEMPORAL_LAYER_NUM\n",
|
||||||
|
ref, pos, temporal_id);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check gop mode */
|
||||||
|
if (!REF_MODE_IS_GLOBAL(ref_mode) && !REF_MODE_IS_ST_MODE(ref_mode)) {
|
||||||
|
mpp_err_f("ref cfg %p st cfg %d with invalid ref mode %x\n",
|
||||||
|
ref, pos, ref_mode);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constrain on head and tail frame */
|
||||||
|
if (pos == 0 || (pos == lt_cfg_cnt - 1)) {
|
||||||
|
if (cfg->is_non_ref) {
|
||||||
|
mpp_err_f("ref cfg %p st cfg %d with invalid non-ref frame on head/tail frame\n",
|
||||||
|
ref, pos);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temporal_id > 0) {
|
||||||
|
mpp_err_f("ref cfg %p st cfg %d with invalid non-zero temporal id %d on head/tail frame\n",
|
||||||
|
ref, pos, temporal_id);
|
||||||
|
ready = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ready)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!cfg->is_non_ref && !(st_tid_used_mask & tid_mask)) {
|
||||||
|
max_st_ref_cnt++;
|
||||||
|
st_tid_used_mask |= tid_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temporal_id > max_st_tid)
|
||||||
|
max_st_tid = temporal_id;
|
||||||
|
|
||||||
|
st_dryrun_length++;
|
||||||
|
st_dryrun_length += cfg->repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ready) {
|
||||||
|
MppEncCpbInfo *cpb_info = &p->cpb_info;
|
||||||
|
MppEncRefs refs = NULL;
|
||||||
|
MPP_RET ret = MPP_OK;
|
||||||
|
|
||||||
|
cpb_info->dpb_size = 0;
|
||||||
|
cpb_info->max_lt_cnt = max_lt_ref_cnt;
|
||||||
|
cpb_info->max_st_cnt = max_st_ref_cnt;
|
||||||
|
cpb_info->max_lt_idx = max_lt_ref_idx;
|
||||||
|
cpb_info->max_st_tid = max_st_tid;
|
||||||
|
cpb_info->lt_gop = lt_dryrun_length;
|
||||||
|
cpb_info->st_gop = st_dryrun_length - 1;
|
||||||
|
|
||||||
|
ret = mpp_enc_refs_init(&refs, NULL);
|
||||||
|
ready = (ret) ? 0 : (ready);
|
||||||
|
ret = mpp_enc_refs_set_cfg(refs, ref);
|
||||||
|
ready = (ret) ? 0 : (ready);
|
||||||
|
ret = mpp_enc_refs_dryrun(refs);
|
||||||
|
ready = (ret) ? 0 : (ready);
|
||||||
|
|
||||||
|
/* update dpb size */
|
||||||
|
ret = mpp_enc_refs_get_cpb_info(refs, cpb_info);
|
||||||
|
ready = (ret) ? 0 : (ready);
|
||||||
|
|
||||||
|
ret = mpp_enc_refs_deinit(&refs);
|
||||||
|
ready = (ret) ? 0 : (ready);
|
||||||
|
} else {
|
||||||
|
mpp_err_f("check ref cfg %p failed\n", ref);
|
||||||
|
}
|
||||||
|
p->ready = ready;
|
||||||
|
|
||||||
|
return ready ? MPP_OK : MPP_NOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_show(MppEncRefCfg ref)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref))
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_ref_cfg_copy(MppEncRefCfg dst, MppEncRefCfg src)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(dst) || check_is_mpp_enc_ref_cfg(src))
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
|
||||||
|
MPP_RET ret = MPP_OK;
|
||||||
|
MppEncRefCfgImpl *d = (MppEncRefCfgImpl *)dst;
|
||||||
|
MppEncRefCfgImpl *s = (MppEncRefCfgImpl *)src;
|
||||||
|
RK_S32 max_lt_cfg = s->max_lt_cfg;
|
||||||
|
RK_S32 max_st_cfg = s->max_st_cfg;
|
||||||
|
|
||||||
|
/* step 1 - free cfg in dst */
|
||||||
|
MPP_FREE(d->lt_cfg);
|
||||||
|
MPP_FREE(d->st_cfg);
|
||||||
|
|
||||||
|
/* step 2 - copy contex from src */
|
||||||
|
memcpy(d, s, sizeof(*d));
|
||||||
|
|
||||||
|
/* step 3 - create new storage and copy lt/st cfg */
|
||||||
|
if (max_lt_cfg) {
|
||||||
|
MppEncRefLtFrmCfg *lt_cfg = mpp_calloc(MppEncRefLtFrmCfg, max_lt_cfg);
|
||||||
|
|
||||||
|
if (NULL == lt_cfg) {
|
||||||
|
mpp_log_f("failed to create %d lt ref cfg\n", max_lt_cfg);
|
||||||
|
ret = MPP_NOK;
|
||||||
|
} else
|
||||||
|
memcpy(lt_cfg, s->lt_cfg, sizeof(lt_cfg[0]) * s->max_lt_cfg);
|
||||||
|
|
||||||
|
d->lt_cfg = lt_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_st_cfg) {
|
||||||
|
MppEncRefStFrmCfg *st_cfg = mpp_calloc(MppEncRefStFrmCfg, max_st_cfg);
|
||||||
|
|
||||||
|
if (NULL == st_cfg) {
|
||||||
|
mpp_log_f("failed to create %d st ref cfg\n", max_st_cfg);
|
||||||
|
ret = MPP_NOK;
|
||||||
|
} else
|
||||||
|
memcpy(st_cfg, s->st_cfg, sizeof(st_cfg[0]) * s->max_st_cfg);
|
||||||
|
|
||||||
|
d->st_cfg = st_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
mpp_enc_ref_cfg_reset(dst);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MppEncCpbInfo *mpp_enc_ref_cfg_get_cpb_info(MppEncRefCfg ref)
|
||||||
|
{
|
||||||
|
if (check_is_mpp_enc_ref_cfg(ref))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
MppEncRefCfgImpl *p = (MppEncRefCfgImpl *)ref;
|
||||||
|
return &p->cpb_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MppEncRefStFrmCfg default_st_ref_cfg = {
|
||||||
|
.is_non_ref = 0,
|
||||||
|
.temporal_id = 0,
|
||||||
|
.ref_mode = REF_TO_PREV_REF_FRM,
|
||||||
|
.ref_arg = 0,
|
||||||
|
.repeat = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const MppEncRefCfgImpl default_ref_cfg = {
|
||||||
|
.name = module_name,
|
||||||
|
.ready = 1,
|
||||||
|
.debug = 0,
|
||||||
|
.max_lt_cfg = 0,
|
||||||
|
.max_st_cfg = 1,
|
||||||
|
.lt_cfg_cnt = 0,
|
||||||
|
.st_cfg_cnt = 1,
|
||||||
|
.lt_cfg = NULL,
|
||||||
|
.st_cfg = &default_st_ref_cfg,
|
||||||
|
.cpb_info = { 1, 0, 1, 0, 0, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
MppEncRefCfg mpp_enc_ref_default(void)
|
||||||
|
{
|
||||||
|
return (MppEncRefCfg)&default_ref_cfg;
|
||||||
|
}
|
752
mpp/base/mpp_enc_refs.cpp
Normal file
752
mpp/base/mpp_enc_refs.cpp
Normal file
@@ -0,0 +1,752 @@
|
|||||||
|
/*
|
||||||
|
* 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_enc_refs"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mpp_env.h"
|
||||||
|
#include "mpp_log.h"
|
||||||
|
#include "mpp_mem.h"
|
||||||
|
#include "mpp_common.h"
|
||||||
|
|
||||||
|
#include "mpp_enc_ref.h"
|
||||||
|
#include "mpp_enc_refs.h"
|
||||||
|
|
||||||
|
#define MAX_CPB_ST_FRM 16
|
||||||
|
#define MAX_CPB_LT_FRM 16
|
||||||
|
#define MAX_CPB_TID_FRM 16
|
||||||
|
#define MAX_CPB_LT_IDX 16
|
||||||
|
#define MAX_CPB_FRM ((MAX_CPB_ST_FRM) + (MAX_CPB_LT_FRM))
|
||||||
|
|
||||||
|
#define MPP_ENC_REFS_DBG_FUNC (0x00000001)
|
||||||
|
#define MPP_ENC_REFS_DBG_FLOW (0x00000002)
|
||||||
|
#define MPP_ENC_REFS_DBG_FRM (0x00000004)
|
||||||
|
#define MPP_ENC_REFS_DBG_SIZE (0x00000008)
|
||||||
|
|
||||||
|
#define enc_refs_dbg_func(fmt, ...) _mpp_dbg_f(enc_refs_debug, MPP_ENC_REFS_DBG_FUNC, fmt, ## __VA_ARGS__)
|
||||||
|
#define enc_refs_dbg_flow(fmt, ...) _mpp_dbg_f(enc_refs_debug, MPP_ENC_REFS_DBG_FLOW, fmt, ## __VA_ARGS__)
|
||||||
|
#define enc_refs_dbg_frm(fmt, ...) _mpp_dbg(enc_refs_debug, MPP_ENC_REFS_DBG_FRM, fmt, ## __VA_ARGS__)
|
||||||
|
#define enc_refs_dbg_size(fmt, ...) _mpp_dbg(enc_refs_debug, MPP_ENC_REFS_DBG_SIZE, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
typedef struct RefsCnt_t {
|
||||||
|
RK_S32 delay;
|
||||||
|
RK_S32 delay_cnt;
|
||||||
|
RK_S32 len;
|
||||||
|
RK_S32 cnt;
|
||||||
|
RK_S32 idx;
|
||||||
|
|
||||||
|
RK_S32 lt_idx;
|
||||||
|
RK_S32 tid;
|
||||||
|
MppEncRefMode ref_mode;
|
||||||
|
RK_S32 ref_arg;
|
||||||
|
} RefsCnt;
|
||||||
|
|
||||||
|
typedef struct EncVirtualCpb_t {
|
||||||
|
MppEncCpbInfo info;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* max 32 reference slot for frame searching
|
||||||
|
* (max 16 lt + max 16 st)
|
||||||
|
* st_slot 0 ~ 15
|
||||||
|
* lt_slot 16 ~ 31
|
||||||
|
*/
|
||||||
|
EncFrmStatus cpb_refs[MAX_CPB_FRM];
|
||||||
|
|
||||||
|
/* max 32 reference mode */
|
||||||
|
EncFrmStatus mode_refs[MAX_CPB_FRM];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reference mode storage with args
|
||||||
|
* st + tid - max 16
|
||||||
|
* lt + idx - max 16
|
||||||
|
*/
|
||||||
|
EncFrmStatus st_tid_refs[MAX_CPB_TID_FRM];
|
||||||
|
EncFrmStatus lt_idx_refs[MAX_CPB_LT_IDX];
|
||||||
|
|
||||||
|
/* long-term counter */
|
||||||
|
/* lt ref will have multiple counters */
|
||||||
|
RefsCnt lt_cnter[MAX_CPB_LT_IDX];
|
||||||
|
|
||||||
|
/* max two list and each list as two frames */
|
||||||
|
EncFrmStatus list0[2];
|
||||||
|
EncFrmStatus list1[2];
|
||||||
|
/* frame kept in cpb */
|
||||||
|
EncFrmStatus cpb_st[2];
|
||||||
|
|
||||||
|
/* runtime record */
|
||||||
|
RK_S32 frm_idx; /* overall frame index */
|
||||||
|
RK_S32 seq_idx; /* sequence index in one gop */
|
||||||
|
RK_S32 seq_cnt;
|
||||||
|
RK_S32 st_cfg_pos;
|
||||||
|
RK_S32 st_cfg_repeat_pos;
|
||||||
|
} EncVirtualCpb;
|
||||||
|
|
||||||
|
typedef struct MppEncRefsImpl_t {
|
||||||
|
MppEncCfgSet *cfg_set;
|
||||||
|
MppEncRefCfgImpl *ref_cfg;
|
||||||
|
|
||||||
|
RK_S32 igop;
|
||||||
|
RK_S32 usr_cfg_updated;
|
||||||
|
MppEncRefFrmUsrCfg usr_cfg;
|
||||||
|
|
||||||
|
EncVirtualCpb cpb;
|
||||||
|
EncVirtualCpb cpb_stash;
|
||||||
|
} MppEncRefsImpl;
|
||||||
|
|
||||||
|
RK_U32 enc_refs_debug = 0;
|
||||||
|
|
||||||
|
void _dump_frm(EncFrmStatus *frm, const char *func, RK_S32 line)
|
||||||
|
{
|
||||||
|
if (frm->is_non_ref) {
|
||||||
|
enc_refs_dbg_frm("%s:%d frm %d %s tid %d non-ref [%x:%d]\n",
|
||||||
|
func, line, frm->seq_idx,
|
||||||
|
frm->is_intra ? "intra" : "inter",
|
||||||
|
frm->temporal_id, frm->ref_mode, frm->ref_arg);
|
||||||
|
} else if (frm->is_lt_ref) {
|
||||||
|
enc_refs_dbg_frm("%s:%d frm %d %s tid %d lt-ref [%x:%d] lt_idx %d\n",
|
||||||
|
func, line, frm->seq_idx,
|
||||||
|
frm->is_intra ? "intra" : "inter",
|
||||||
|
frm->temporal_id, frm->ref_mode, frm->ref_arg,
|
||||||
|
frm->lt_idx);
|
||||||
|
} else {
|
||||||
|
enc_refs_dbg_frm("%s:%d frm %d %s tid %d st-ref [%x:%d]\n",
|
||||||
|
func, line, frm->seq_idx,
|
||||||
|
frm->is_intra ? "intra" : "inter",
|
||||||
|
frm->temporal_id, frm->ref_mode, frm->ref_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_init(MppEncRefs *refs, MppEncCfgSet *cfg)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_NULL_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p cfg %p\n", refs, cfg);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = mpp_calloc(MppEncRefsImpl, 1);
|
||||||
|
*refs = p;
|
||||||
|
if (NULL == p) {
|
||||||
|
mpp_err_f("create refs_impl failed\n");
|
||||||
|
return MPP_ERR_NULL_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->cfg_set = cfg;
|
||||||
|
|
||||||
|
mpp_env_get_u32("enc_refs_debug", &enc_refs_debug, 0);
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p cfg %p\n", p, cfg);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_deinit(MppEncRefs *refs)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)(*refs);
|
||||||
|
MPP_FREE(p);
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_set_cfg(MppEncRefs refs, MppEncRefCfg ref_cfg)
|
||||||
|
{
|
||||||
|
if (NULL == refs || (ref_cfg && check_is_mpp_enc_ref_cfg(ref_cfg))) {
|
||||||
|
mpp_err_f("invalid input refs %p ref_cfg %p\n", refs, ref_cfg);
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p cfg %p\n", refs, ref_cfg);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
EncVirtualCpb *cpb = &p->cpb;
|
||||||
|
MppEncRefCfgImpl *cfg = NULL;
|
||||||
|
|
||||||
|
if (NULL == ref_cfg) {
|
||||||
|
if (p->cfg_set)
|
||||||
|
ref_cfg = p->cfg_set->ref_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == ref_cfg)
|
||||||
|
ref_cfg = mpp_enc_ref_default();
|
||||||
|
|
||||||
|
cfg = (MppEncRefCfgImpl *)ref_cfg;
|
||||||
|
|
||||||
|
p->ref_cfg = cfg;
|
||||||
|
|
||||||
|
if (cfg->lt_cfg_cnt) {
|
||||||
|
RK_S32 i;
|
||||||
|
|
||||||
|
mpp_assert(cfg->lt_cfg_cnt < MAX_CPB_LT_FRM);
|
||||||
|
|
||||||
|
for (i = 0; i < cfg->lt_cfg_cnt; i++) {
|
||||||
|
RefsCnt *lt_cnt = &cpb->lt_cnter[i];
|
||||||
|
MppEncRefLtFrmCfg *lt_cfg = &cfg->lt_cfg[i];
|
||||||
|
|
||||||
|
lt_cnt->delay = lt_cfg->lt_delay;
|
||||||
|
lt_cnt->delay_cnt = lt_cfg->lt_delay;
|
||||||
|
lt_cnt->len = lt_cfg->lt_gap;
|
||||||
|
lt_cnt->lt_idx = lt_cfg->lt_idx;
|
||||||
|
lt_cnt->tid = lt_cfg->temporal_id;
|
||||||
|
lt_cnt->ref_mode = lt_cfg->ref_mode;
|
||||||
|
lt_cnt->ref_arg = lt_cfg->ref_arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MppEncCpbInfo *info = &cpb->info;
|
||||||
|
memcpy(info, &cfg->cpb_info, sizeof(cfg->cpb_info));
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("ref_cfg cpb size: lt %d st %d max lt_idx %d tid %d\n",
|
||||||
|
info->max_lt_cnt, info->max_st_cnt,
|
||||||
|
info->max_lt_idx, info->max_st_tid);
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p cfg %p\n", refs, ref_cfg);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup_cpb_refs(EncVirtualCpb *cpb)
|
||||||
|
{
|
||||||
|
RK_U32 i;
|
||||||
|
|
||||||
|
memset(cpb->cpb_refs, 0, sizeof(cpb->cpb_refs));
|
||||||
|
memset(cpb->mode_refs, 0, sizeof(cpb->mode_refs));
|
||||||
|
memset(cpb->st_tid_refs, 0, sizeof(cpb->st_tid_refs));
|
||||||
|
memset(cpb->lt_idx_refs, 0, sizeof(cpb->lt_idx_refs));
|
||||||
|
memset(cpb->list0, 0, sizeof(cpb->list0));
|
||||||
|
memset(cpb->list1, 0, sizeof(cpb->list1));
|
||||||
|
memset(cpb->cpb_st, 0, sizeof(cpb->cpb_st));
|
||||||
|
|
||||||
|
cpb->seq_idx = 0;
|
||||||
|
cpb->seq_cnt++;
|
||||||
|
cpb->st_cfg_pos = 0;
|
||||||
|
cpb->st_cfg_repeat_pos = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < MPP_ARRAY_ELEMS(cpb->lt_cnter); i++) {
|
||||||
|
RefsCnt *lt_cnt = &cpb->lt_cnter[i];
|
||||||
|
|
||||||
|
lt_cnt->delay_cnt = lt_cnt->delay;
|
||||||
|
lt_cnt->cnt = 0;
|
||||||
|
lt_cnt->idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_st_cfg_to_frm(EncFrmStatus *frm, RK_S32 seq_idx,
|
||||||
|
MppEncRefStFrmCfg *st_cfg)
|
||||||
|
{
|
||||||
|
memset(frm, 0, sizeof(*frm));
|
||||||
|
|
||||||
|
frm->seq_idx = seq_idx;
|
||||||
|
frm->valid = 1;
|
||||||
|
frm->is_idr = (seq_idx == 0);
|
||||||
|
frm->is_intra = frm->is_idr;
|
||||||
|
frm->is_non_ref = st_cfg->is_non_ref;
|
||||||
|
frm->is_lt_ref = 0;
|
||||||
|
frm->temporal_id = st_cfg->temporal_id;
|
||||||
|
frm->ref_mode = st_cfg->ref_mode;
|
||||||
|
frm->ref_arg = st_cfg->ref_arg;
|
||||||
|
dump_frm(frm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_lt_cfg_to_frm(EncFrmStatus *frm, RefsCnt *lt_cfg)
|
||||||
|
{
|
||||||
|
frm->is_non_ref = 0;
|
||||||
|
frm->is_lt_ref = 1;
|
||||||
|
frm->temporal_id = lt_cfg->tid;
|
||||||
|
frm->lt_idx = lt_cfg->lt_idx;
|
||||||
|
|
||||||
|
if (lt_cfg->ref_mode != REF_TO_ST_REF_SETUP) {
|
||||||
|
frm->ref_mode = lt_cfg->ref_mode;
|
||||||
|
frm->ref_arg = lt_cfg->ref_arg;
|
||||||
|
}
|
||||||
|
dump_frm(frm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EncFrmStatus *get_ref_from_cpb(EncVirtualCpb *cpb, EncFrmStatus *frm)
|
||||||
|
{
|
||||||
|
MppEncRefMode ref_mode = frm->ref_mode;
|
||||||
|
RK_S32 ref_arg = frm->ref_arg;
|
||||||
|
|
||||||
|
if (frm->is_intra)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
EncFrmStatus *ref = NULL;
|
||||||
|
|
||||||
|
/* step 3.1 find seq_idx by mode and arg */
|
||||||
|
switch (ref_mode) {
|
||||||
|
case REF_TO_PREV_REF_FRM :
|
||||||
|
case REF_TO_PREV_ST_REF :
|
||||||
|
case REF_TO_PREV_LT_REF :
|
||||||
|
case REF_TO_PREV_INTRA : {
|
||||||
|
ref = &cpb->mode_refs[ref_mode];
|
||||||
|
} break;
|
||||||
|
case REF_TO_TEMPORAL_LAYER : {
|
||||||
|
ref = &cpb->st_tid_refs[ref_arg];
|
||||||
|
} break;
|
||||||
|
case REF_TO_LT_REF_IDX : {
|
||||||
|
ref = &cpb->lt_idx_refs[ref_arg];
|
||||||
|
} break;
|
||||||
|
case REF_TO_ST_PREV_N_REF : {
|
||||||
|
ref = &cpb->cpb_refs[ref_arg];
|
||||||
|
} break;
|
||||||
|
case REF_TO_ST_REF_SETUP :
|
||||||
|
default : {
|
||||||
|
mpp_err_f("frm %d not supported ref mode 0x%x\n", frm->seq_idx, ref_mode);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref) {
|
||||||
|
if (ref->valid)
|
||||||
|
enc_refs_dbg_flow("frm %d ref mode %d arg %d -> seq %d %s idx %d\n",
|
||||||
|
frm->seq_idx, ref_mode, ref_arg, ref->seq_idx,
|
||||||
|
ref->is_lt_ref ? "lt" : "st",
|
||||||
|
ref->is_lt_ref ? ref->lt_idx : 0);
|
||||||
|
else
|
||||||
|
mpp_err_f("frm %d found ref %d but it is invalid\n",
|
||||||
|
frm->seq_idx, ref->seq_idx);
|
||||||
|
} else {
|
||||||
|
ref = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RK_S32 check_ref_cpb_pos(EncVirtualCpb *cpb, EncFrmStatus *frm)
|
||||||
|
{
|
||||||
|
RK_S32 seq_idx = frm->seq_idx;
|
||||||
|
RK_S32 found = 0;
|
||||||
|
RK_S32 pos = -1;
|
||||||
|
|
||||||
|
if (!frm->valid || frm->is_non_ref) {
|
||||||
|
enc_refs_dbg_flow("frm %d is not valid ref frm\n", seq_idx);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frm->is_lt_ref) {
|
||||||
|
/* find same lt_idx */
|
||||||
|
for (pos = 0; pos < MAX_CPB_LT_FRM; pos++) {
|
||||||
|
RK_S32 cpb_idx = pos + MAX_CPB_ST_FRM;
|
||||||
|
EncFrmStatus *cpb_ref = &cpb->cpb_refs[cpb_idx];
|
||||||
|
|
||||||
|
if (cpb_ref->valid && cpb_ref->lt_idx == frm->lt_idx) {
|
||||||
|
pos = cpb_idx;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* search seq_idx in cpb to check the st cpb size */
|
||||||
|
for (pos = 0; pos < MAX_CPB_ST_FRM; pos++) {
|
||||||
|
EncFrmStatus *cpb_ref = &cpb->cpb_refs[pos];
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("matching ref %d at pos %d %d\n",
|
||||||
|
seq_idx, pos, cpb_ref->seq_idx);
|
||||||
|
|
||||||
|
if (cpb_ref->valid && cpb_ref->seq_idx == seq_idx) {
|
||||||
|
enc_refs_dbg_flow("found ref %d at pos %d\n", seq_idx, pos);
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
mpp_err_f("frm %d can NOT be found in st refs!!\n", seq_idx);
|
||||||
|
pos = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_cpb_status(EncVirtualCpb *cpb, EncFrmStatus *refs)
|
||||||
|
{
|
||||||
|
EncFrmStatus *ref = &cpb->cpb_refs[MAX_CPB_ST_FRM];
|
||||||
|
MppEncCpbInfo *info = &cpb->info;
|
||||||
|
RK_S32 lt_ref_cnt = 0;
|
||||||
|
RK_S32 st_ref_cnt = 0;
|
||||||
|
RK_S32 ref_cnt = 0;
|
||||||
|
RK_S32 i;
|
||||||
|
|
||||||
|
/* save lt ref */
|
||||||
|
for (i = 0; i < info->max_lt_cnt; i++, ref++) {
|
||||||
|
if (!ref->valid || ref->is_non_ref || !ref->is_lt_ref)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mpp_assert(!ref->is_non_ref);
|
||||||
|
mpp_assert(ref->is_lt_ref);
|
||||||
|
mpp_assert(ref->lt_idx >= 0);
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("save lt ref %d to slot %d\n", ref->seq_idx, ref_cnt);
|
||||||
|
refs[ref_cnt++].val = ref->val;
|
||||||
|
lt_ref_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = &cpb->cpb_refs[0];
|
||||||
|
/* save st ref */
|
||||||
|
for (i = 0; i < info->max_st_cnt; i++, ref++) {
|
||||||
|
if (!ref->valid || ref->is_non_ref || ref->is_lt_ref)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mpp_assert(!ref->is_non_ref);
|
||||||
|
mpp_assert(!ref->is_lt_ref);
|
||||||
|
mpp_assert(ref->temporal_id >= 0);
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("save st ref %d to slot %d\n", ref->seq_idx, ref_cnt);
|
||||||
|
refs[ref_cnt++].val = ref->val;
|
||||||
|
st_ref_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("save ref total %d lt %d st %d\n", ref_cnt, lt_ref_cnt, st_ref_cnt);
|
||||||
|
for (i = 0; i < ref_cnt; i++)
|
||||||
|
dump_frm(&refs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void store_ref_to_cpb(EncVirtualCpb *cpb, EncFrmStatus *frm)
|
||||||
|
{
|
||||||
|
RK_S32 seq_idx = frm->seq_idx;
|
||||||
|
RK_S32 lt_idx = frm->lt_idx;
|
||||||
|
RK_S32 tid = frm->temporal_id;
|
||||||
|
RK_S32 i;
|
||||||
|
|
||||||
|
mpp_assert(frm->valid);
|
||||||
|
mpp_assert(lt_idx < MAX_CPB_LT_IDX);
|
||||||
|
mpp_assert(tid < MAX_CPB_LT_FRM);
|
||||||
|
|
||||||
|
/* non-ref do not save to cpb */
|
||||||
|
if (frm->is_non_ref)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
if (frm->is_intra)
|
||||||
|
cpb->mode_refs[REF_TO_PREV_INTRA].val = frm->val;
|
||||||
|
|
||||||
|
if (frm->is_lt_ref) {
|
||||||
|
cpb->lt_idx_refs[lt_idx].val = frm->val;
|
||||||
|
cpb->mode_refs[REF_TO_PREV_REF_FRM].val = frm->val;
|
||||||
|
cpb->mode_refs[REF_TO_PREV_LT_REF].val = frm->val;
|
||||||
|
|
||||||
|
RK_S32 found = 0;
|
||||||
|
EncFrmStatus *cpb_ref = NULL;
|
||||||
|
|
||||||
|
/* find same lt_idx and replace */
|
||||||
|
for (i = 0; i < MAX_CPB_LT_FRM; i++) {
|
||||||
|
RK_S32 cpb_idx = i + MAX_CPB_ST_FRM;
|
||||||
|
cpb_ref = &cpb->cpb_refs[cpb_idx];
|
||||||
|
|
||||||
|
if (!cpb_ref->valid) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (cpb_ref->lt_idx == lt_idx) {
|
||||||
|
found = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
cpb_ref->val = frm->val;
|
||||||
|
enc_refs_dbg_flow("frm %d with lt idx %d %s to pos %d\n",
|
||||||
|
seq_idx, lt_idx, (found == 1) ? "add" : "replace", i);
|
||||||
|
} else {
|
||||||
|
mpp_err_f("frm %d with lt idx %d found no place to add or relace\n",
|
||||||
|
seq_idx, lt_idx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* do normal st sliding window */
|
||||||
|
cpb->st_tid_refs[tid].val = frm->val;
|
||||||
|
cpb->mode_refs[REF_TO_PREV_REF_FRM].val = frm->val;
|
||||||
|
cpb->mode_refs[REF_TO_PREV_ST_REF].val = frm->val;
|
||||||
|
|
||||||
|
|
||||||
|
for (i = MAX_CPB_ST_FRM - 1; i > 0; i--)
|
||||||
|
cpb->cpb_refs[i - 1].val = cpb->cpb_refs[i].val;
|
||||||
|
|
||||||
|
cpb->cpb_refs[0].val = frm->val;
|
||||||
|
|
||||||
|
// TODO: Add prev intra valid check?
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("dumping cpb refs status start\n");
|
||||||
|
for (i = 0; i < MAX_CPB_FRM; i++) {
|
||||||
|
if (cpb->cpb_refs[i].valid)
|
||||||
|
dump_frm(&cpb->cpb_refs[i]);
|
||||||
|
}
|
||||||
|
enc_refs_dbg_flow("dumping cpb refs status done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_dryrun(MppEncRefs refs)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
MppEncRefCfgImpl *cfg = p->ref_cfg;
|
||||||
|
MppEncRefStFrmCfg *st_cfg = cfg->st_cfg;
|
||||||
|
EncVirtualCpb *cpb = &p->cpb;
|
||||||
|
MppEncCpbInfo *info = &cpb->info;
|
||||||
|
RK_S32 lt_cfg_cnt = cfg->lt_cfg_cnt;
|
||||||
|
RK_S32 st_cfg_cnt = cfg->st_cfg_cnt;
|
||||||
|
RK_S32 cpb_st_used_size = 0;
|
||||||
|
RK_S32 seq_idx = 0;
|
||||||
|
RK_S32 st_idx;
|
||||||
|
|
||||||
|
if (cfg->ready)
|
||||||
|
goto DONE;
|
||||||
|
|
||||||
|
cleanup_cpb_refs(cpb);
|
||||||
|
|
||||||
|
enc_refs_dbg_flow("dryrun start: lt_cfg %d st_cfg %d\n",
|
||||||
|
lt_cfg_cnt, st_cfg_cnt);
|
||||||
|
|
||||||
|
for (st_idx = 0; st_idx < st_cfg_cnt; st_idx++, st_cfg++) {
|
||||||
|
EncFrmStatus frm;
|
||||||
|
RK_S32 repeat = (st_cfg->repeat) ? st_cfg->repeat : 1;
|
||||||
|
|
||||||
|
while (repeat-- > 0) {
|
||||||
|
/* step 1. updated by st_cfg */
|
||||||
|
set_st_cfg_to_frm(&frm, seq_idx++, st_cfg);
|
||||||
|
|
||||||
|
/* step 2. updated by lt_cfg */
|
||||||
|
RefsCnt *lt_cfg = &cpb->lt_cnter[0];
|
||||||
|
RK_S32 set_to_lt = 0;
|
||||||
|
RK_S32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < lt_cfg_cnt; i++, lt_cfg++) {
|
||||||
|
if (lt_cfg->delay_cnt)
|
||||||
|
lt_cfg->delay_cnt--;
|
||||||
|
|
||||||
|
if (lt_cfg->delay_cnt)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!set_to_lt) {
|
||||||
|
if (!lt_cfg->cnt) {
|
||||||
|
set_lt_cfg_to_frm(&frm, lt_cfg);
|
||||||
|
set_to_lt = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lt_cfg->cnt++;
|
||||||
|
if (lt_cfg->cnt >= lt_cfg->len) {
|
||||||
|
lt_cfg->cnt = 0;
|
||||||
|
lt_cfg->idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* step 3. try find ref by the ref_mode and update used cpb size */
|
||||||
|
EncFrmStatus *ref = get_ref_from_cpb(cpb, &frm);
|
||||||
|
|
||||||
|
if (ref) {
|
||||||
|
RK_S32 cpb_pos = check_ref_cpb_pos(cpb, ref);
|
||||||
|
|
||||||
|
if (cpb_pos < MAX_CPB_ST_FRM) {
|
||||||
|
if (cpb_st_used_size < cpb_pos + 1) {
|
||||||
|
cpb_st_used_size = cpb_pos + 1;
|
||||||
|
enc_refs_dbg_flow("cpb_st_used_size update to %d\n", cpb_st_used_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* step 4. store frame according to status */
|
||||||
|
store_ref_to_cpb(cpb, &frm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_cpb_refs(cpb);
|
||||||
|
info->max_st_cnt = cpb_st_used_size;
|
||||||
|
|
||||||
|
DONE:
|
||||||
|
info->dpb_size = info->max_lt_cnt + info->max_st_cnt;
|
||||||
|
|
||||||
|
enc_refs_dbg_size("dryrun success: cpb size %d\n", info->dpb_size);
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_set_usr_cfg(MppEncRefs refs, MppEncRefFrmUsrCfg *cfg)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
memcpy(&p->usr_cfg, cfg, sizeof(p->usr_cfg));
|
||||||
|
p->usr_cfg_updated = 1;
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_get_cpb_info(MppEncRefs refs, MppEncCpbInfo *info)
|
||||||
|
{
|
||||||
|
if (NULL == refs || NULL == info) {
|
||||||
|
mpp_err_f("invalid input refs %p info %p\n", refs, info);
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
memcpy(info, &p->cpb.info, sizeof(*info));
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_get_cpb(MppEncRefs refs, EncCpbStatus *status)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
MppEncCfgSet *cfg_set = p->cfg_set;
|
||||||
|
MppEncRefCfgImpl *cfg = p->ref_cfg;
|
||||||
|
EncVirtualCpb *cpb = &p->cpb;
|
||||||
|
MppEncRefStFrmCfg *st_cfg = &cfg->st_cfg[cpb->st_cfg_pos];
|
||||||
|
EncFrmStatus *frm = &status->curr;
|
||||||
|
EncFrmStatus *ref = &status->refr;
|
||||||
|
RefsCnt *lt_cfg = cpb->lt_cnter;
|
||||||
|
RK_S32 set_to_lt = 0;
|
||||||
|
RK_S32 i;
|
||||||
|
|
||||||
|
/* step 1. check igop from cfg_set */
|
||||||
|
if (cfg_set->rc.gop != p->igop) {
|
||||||
|
p->igop = cfg_set->rc.gop;
|
||||||
|
cleanup_cpb_refs(cpb);
|
||||||
|
} if (p->igop && cpb->seq_idx >= p->igop) {
|
||||||
|
/* update seq_idx for igop loop */
|
||||||
|
cleanup_cpb_refs(cpb);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpb->frm_idx++;
|
||||||
|
/* step 2. updated by st_cfg */
|
||||||
|
set_st_cfg_to_frm(frm, cpb->seq_idx++, st_cfg);
|
||||||
|
|
||||||
|
/* update st_cfg for st_cfg loop */
|
||||||
|
cpb->st_cfg_repeat_pos++;
|
||||||
|
if (cpb->st_cfg_repeat_pos > st_cfg->repeat) {
|
||||||
|
cpb->st_cfg_repeat_pos = 0;
|
||||||
|
cpb->st_cfg_pos++;
|
||||||
|
|
||||||
|
/* NOTE: second loop will start from 1 */
|
||||||
|
if (cpb->st_cfg_pos >= cfg->st_cfg_cnt) {
|
||||||
|
if (cfg->st_cfg_cnt > 1)
|
||||||
|
cpb->st_cfg_pos = 1;
|
||||||
|
else
|
||||||
|
cpb->st_cfg_pos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lt_cfg = p->cpb.lt_cnter;
|
||||||
|
|
||||||
|
/* step 3. updated by lt_cfg */
|
||||||
|
for (i = 0; i < cfg->lt_cfg_cnt; i++, lt_cfg++) {
|
||||||
|
if (lt_cfg->delay_cnt)
|
||||||
|
lt_cfg->delay_cnt--;
|
||||||
|
|
||||||
|
if (lt_cfg->delay_cnt)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!set_to_lt) {
|
||||||
|
if (!lt_cfg->cnt) {
|
||||||
|
set_lt_cfg_to_frm(frm, lt_cfg);
|
||||||
|
set_to_lt = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lt_cfg->cnt++;
|
||||||
|
if (lt_cfg->cnt >= lt_cfg->len) {
|
||||||
|
lt_cfg->cnt = 0;
|
||||||
|
lt_cfg->idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* step 4. try find ref by the ref_mode */
|
||||||
|
EncFrmStatus *ref_found = get_ref_from_cpb(&p->cpb, frm);
|
||||||
|
if (ref_found) {
|
||||||
|
RK_S32 cpb_idx = check_ref_cpb_pos(&p->cpb, ref_found);
|
||||||
|
|
||||||
|
mpp_assert(cpb_idx >= 0);
|
||||||
|
cpb->list0[0].val = ref->val;
|
||||||
|
ref->val = ref_found->val;
|
||||||
|
} else
|
||||||
|
ref->val = 0;
|
||||||
|
|
||||||
|
/* step 5. generate cpb init */
|
||||||
|
memset(status->init, 0, sizeof(status->init));
|
||||||
|
save_cpb_status(&p->cpb, status->init);
|
||||||
|
// TODO: cpb_init must be the same to cpb_final
|
||||||
|
|
||||||
|
/* step 6. store frame according to status */
|
||||||
|
store_ref_to_cpb(&p->cpb, frm);
|
||||||
|
|
||||||
|
/* step 7. generate cpb final */
|
||||||
|
memset(status->final, 0, sizeof(status->final));
|
||||||
|
save_cpb_status(&p->cpb, status->final);
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_stash(MppEncRefs refs)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
memcpy(&p->cpb_stash, &p->cpb, sizeof(p->cpb_stash));
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPP_RET mpp_enc_refs_rollback(MppEncRefs refs)
|
||||||
|
{
|
||||||
|
if (NULL == refs) {
|
||||||
|
mpp_err_f("invalid NULL input refs\n");
|
||||||
|
return MPP_ERR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc_refs_dbg_func("enter %p\n", refs);
|
||||||
|
|
||||||
|
MppEncRefsImpl *p = (MppEncRefsImpl *)refs;
|
||||||
|
memcpy(&p->cpb, &p->cpb_stash, sizeof(p->cpb));
|
||||||
|
|
||||||
|
enc_refs_dbg_func("leave %p\n", refs);
|
||||||
|
return MPP_OK;
|
||||||
|
}
|
@@ -36,3 +36,6 @@ add_mpp_base_test(mpp_trie)
|
|||||||
|
|
||||||
# mpp_enc_cfg unit test
|
# mpp_enc_cfg unit test
|
||||||
add_mpp_base_test(mpp_enc_cfg)
|
add_mpp_base_test(mpp_enc_cfg)
|
||||||
|
|
||||||
|
# mpp_enc_ref unit test
|
||||||
|
add_mpp_base_test(mpp_enc_ref)
|
||||||
|
176
mpp/base/test/mpp_enc_ref_test.c
Normal file
176
mpp/base/test/mpp_enc_ref_test.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* 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_enc_ref_test"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mpp_log.h"
|
||||||
|
|
||||||
|
#include "rk_venc_ref.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
MPP_RET ret = MPP_OK;
|
||||||
|
RK_S32 lt_cnt = 0;
|
||||||
|
RK_S32 st_cnt = 0;
|
||||||
|
MppEncRefCfg ref = NULL;
|
||||||
|
MppEncRefLtFrmCfg lt_ref[4];
|
||||||
|
MppEncRefStFrmCfg st_ref[16];
|
||||||
|
|
||||||
|
memset(<_ref, 0, sizeof(lt_ref));
|
||||||
|
memset(&st_ref, 0, sizeof(st_ref));
|
||||||
|
|
||||||
|
mpp_log("mpp_enc_ref_test start\n");
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_init(&ref);
|
||||||
|
|
||||||
|
mpp_log("mpp_enc_ref_test tsvc4 ref info generation start\n");
|
||||||
|
|
||||||
|
lt_cnt = 1;
|
||||||
|
st_cnt = 9;
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_set_cfg_cnt(ref, lt_cnt, st_cnt);
|
||||||
|
|
||||||
|
/* set 8 frame lt-ref gap */
|
||||||
|
lt_ref[0].lt_idx = 0;
|
||||||
|
lt_ref[0].temporal_id = 0;
|
||||||
|
lt_ref[0].ref_mode = REF_TO_PREV_LT_REF;
|
||||||
|
lt_ref[0].lt_gap = 8;
|
||||||
|
lt_ref[0].lt_delay = 0;
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_add_lt_cfg(ref, 1, lt_ref);
|
||||||
|
|
||||||
|
/* set tsvc4 st-ref struct */
|
||||||
|
/* st 0 layer 0 - ref */
|
||||||
|
st_ref[0].is_non_ref = 0;
|
||||||
|
st_ref[0].temporal_id = 0;
|
||||||
|
st_ref[0].ref_mode = REF_TO_TEMPORAL_LAYER;
|
||||||
|
st_ref[0].ref_arg = 0;
|
||||||
|
st_ref[0].repeat = 0;
|
||||||
|
/* st 1 layer 3 - non-ref */
|
||||||
|
st_ref[1].is_non_ref = 1;
|
||||||
|
st_ref[1].temporal_id = 3;
|
||||||
|
st_ref[1].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[1].ref_arg = 0;
|
||||||
|
st_ref[1].repeat = 0;
|
||||||
|
/* st 2 layer 2 - ref */
|
||||||
|
st_ref[2].is_non_ref = 0;
|
||||||
|
st_ref[2].temporal_id = 2;
|
||||||
|
st_ref[2].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[2].ref_arg = 0;
|
||||||
|
st_ref[2].repeat = 0;
|
||||||
|
/* st 3 layer 3 - non-ref */
|
||||||
|
st_ref[3].is_non_ref = 1;
|
||||||
|
st_ref[3].temporal_id = 3;
|
||||||
|
st_ref[3].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[3].ref_arg = 0;
|
||||||
|
st_ref[3].repeat = 0;
|
||||||
|
/* st 4 layer 1 - ref */
|
||||||
|
st_ref[4].is_non_ref = 0;
|
||||||
|
st_ref[4].temporal_id = 1;
|
||||||
|
st_ref[4].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[4].ref_arg = 0;
|
||||||
|
st_ref[4].repeat = 0;
|
||||||
|
/* st 5 layer 3 - non-ref */
|
||||||
|
st_ref[5].is_non_ref = 1;
|
||||||
|
st_ref[5].temporal_id = 3;
|
||||||
|
st_ref[5].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[5].ref_arg = 0;
|
||||||
|
st_ref[5].repeat = 0;
|
||||||
|
/* st 6 layer 2 - ref */
|
||||||
|
st_ref[6].is_non_ref = 0;
|
||||||
|
st_ref[6].temporal_id = 2;
|
||||||
|
st_ref[6].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[6].ref_arg = 0;
|
||||||
|
st_ref[6].repeat = 0;
|
||||||
|
/* st 7 layer 3 - non-ref */
|
||||||
|
st_ref[7].is_non_ref = 1;
|
||||||
|
st_ref[7].temporal_id = 3;
|
||||||
|
st_ref[7].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[7].ref_arg = 0;
|
||||||
|
st_ref[7].repeat = 0;
|
||||||
|
/* st 8 layer 0 - ref */
|
||||||
|
st_ref[8].is_non_ref = 0;
|
||||||
|
st_ref[8].temporal_id = 0;
|
||||||
|
st_ref[8].ref_mode = REF_TO_TEMPORAL_LAYER;
|
||||||
|
st_ref[8].ref_arg = 0;
|
||||||
|
st_ref[8].repeat = 0;
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_add_st_cfg(ref, 9, st_ref);
|
||||||
|
|
||||||
|
/* check and get dpb size */
|
||||||
|
mpp_log("mpp_enc_ref_test tsvc4 ref info verification start\n");
|
||||||
|
ret = mpp_enc_ref_cfg_check(ref);
|
||||||
|
mpp_log("mpp_enc_ref_test tsvc4 ref info verification ret %d\n", ret);
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_show(ref);
|
||||||
|
|
||||||
|
/* reset for next config */
|
||||||
|
ret = mpp_enc_ref_cfg_reset(ref);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
mpp_log("mpp_enc_ref_test smartp ref info generation start\n");
|
||||||
|
|
||||||
|
/* typical smartp config */
|
||||||
|
lt_cnt = 1;
|
||||||
|
st_cnt = 3;
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_set_cfg_cnt(ref, lt_cnt, st_cnt);
|
||||||
|
|
||||||
|
memset(<_ref, 0, sizeof(lt_ref));
|
||||||
|
memset(&st_ref, 0, sizeof(st_ref));
|
||||||
|
|
||||||
|
/* set 300 frame lt-ref gap */
|
||||||
|
lt_ref[0].lt_idx = 0;
|
||||||
|
lt_ref[0].temporal_id = 0;
|
||||||
|
lt_ref[0].ref_mode = REF_TO_PREV_INTRA;
|
||||||
|
lt_ref[0].lt_gap = 300;
|
||||||
|
lt_ref[0].lt_delay = 0;
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_add_lt_cfg(ref, 1, lt_ref);
|
||||||
|
|
||||||
|
st_ref[0].is_non_ref = 0;
|
||||||
|
st_ref[0].temporal_id = 0;
|
||||||
|
st_ref[0].ref_mode = REF_TO_PREV_LT_REF;
|
||||||
|
st_ref[0].ref_arg = 0;
|
||||||
|
st_ref[0].repeat = 0;
|
||||||
|
|
||||||
|
st_ref[1].is_non_ref = 0;
|
||||||
|
st_ref[1].temporal_id = 0;
|
||||||
|
st_ref[1].ref_mode = REF_TO_PREV_REF_FRM;
|
||||||
|
st_ref[1].ref_arg = 0;
|
||||||
|
st_ref[1].repeat = 299;
|
||||||
|
|
||||||
|
st_ref[2].is_non_ref = 0;
|
||||||
|
st_ref[2].temporal_id = 0;
|
||||||
|
st_ref[2].ref_mode = REF_TO_PREV_LT_REF;
|
||||||
|
st_ref[2].ref_arg = 0;
|
||||||
|
st_ref[2].repeat = 0;
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_add_st_cfg(ref, 3, st_ref);
|
||||||
|
|
||||||
|
mpp_log("mpp_enc_ref_test smartp ref info verification start\n");
|
||||||
|
ret = mpp_enc_ref_cfg_check(ref);
|
||||||
|
mpp_log("mpp_enc_ref_test smartp ref info verification ret %d\n", ret);
|
||||||
|
|
||||||
|
ret = mpp_enc_ref_cfg_deinit(&ref);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mpp_log("mpp_enc_ref_test %s\n", ret ? "failed" : "success");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
@@ -18,6 +18,7 @@
|
|||||||
#define __MPP_ENC_CFG_H__
|
#define __MPP_ENC_CFG_H__
|
||||||
|
|
||||||
#include "rk_venc_cmd.h"
|
#include "rk_venc_cmd.h"
|
||||||
|
#include "rk_venc_ref.h"
|
||||||
#include "rc_data.h"
|
#include "rc_data.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -36,6 +37,7 @@ typedef struct MppEncCfgSet_t {
|
|||||||
MppEncCodecCfg codec;
|
MppEncCodecCfg codec;
|
||||||
|
|
||||||
MppEncSliceSplit split;
|
MppEncSliceSplit split;
|
||||||
|
MppEncRefCfg ref_cfg;
|
||||||
MppEncROICfg roi;
|
MppEncROICfg roi;
|
||||||
MppEncOSDPltCfg plt_cfg;
|
MppEncOSDPltCfg plt_cfg;
|
||||||
MppEncOSDPlt plt_data;
|
MppEncOSDPlt plt_data;
|
||||||
|
Reference in New Issue
Block a user