/*
|
* 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.
|
*/
|
|
#define MODULE_TAG "rc"
|
|
#include <math.h>
|
#include <memory.h>
|
|
#include "mpp_env.h"
|
#include "mpp_mem.h"
|
#include "mpp_list.h"
|
#include "mpp_common.h"
|
|
#include "rc_debug.h"
|
#include "rc.h"
|
#include "rc_impl.h"
|
#include "rc_base.h"
|
|
typedef struct MppRcImpl_t {
|
void *ctx;
|
const RcImplApi *api;
|
RcCfg cfg;
|
|
RcFpsCfg fps;
|
RK_S32 frm_cnt;
|
|
RK_U32 frm_send;
|
RK_U32 frm_done;
|
} MppRcImpl;
|
|
RK_U32 rc_debug = 0;
|
|
const static char default_rc_api[] = "default";
|
|
MPP_RET rc_init(RcCtx *ctx, MppCodingType type, const char **request_name)
|
{
|
MPP_RET ret = MPP_NOK;
|
MppRcImpl *p = NULL;
|
const char *name = NULL;
|
|
mpp_env_get_u32("rc_debug", &rc_debug, 0);
|
|
if (NULL == request_name || NULL == *request_name)
|
name = default_rc_api;
|
else
|
name = *request_name;
|
|
rc_dbg_func("enter type %x name %s\n", type, name);
|
|
RcImplApi *api = RcImplApiService::get_instance()->api_get(type, name);
|
|
mpp_assert(api);
|
|
if (api) {
|
void *rc_ctx = mpp_calloc_size(void, api->ctx_size);
|
p = mpp_calloc(MppRcImpl, 1);
|
|
if (NULL == p || NULL == rc_ctx) {
|
mpp_err_f("failed to create context size %d\n", api->ctx_size);
|
MPP_FREE(p);
|
MPP_FREE(rc_ctx);
|
ret = MPP_ERR_MALLOC;
|
} else {
|
p->ctx = rc_ctx;
|
p->api = api;
|
p->frm_cnt = -1;
|
if (request_name && *request_name)
|
mpp_log("using rc impl %s\n", api->name);
|
ret = MPP_OK;
|
}
|
}
|
|
*ctx = p;
|
if (request_name)
|
*request_name = name;
|
|
rc_dbg_func("leave %p\n", p);
|
|
return ret;
|
}
|
|
MPP_RET rc_deinit(RcCtx ctx)
|
{
|
MppRcImpl *p = (MppRcImpl *)ctx;
|
const RcImplApi *api = p->api;
|
MPP_RET ret = MPP_OK;
|
|
rc_dbg_func("enter %p\n", ctx);
|
|
if (api && api->deinit && p->ctx) {
|
ret = api->deinit(p->ctx);
|
MPP_FREE(p->ctx);
|
}
|
|
MPP_FREE(p);
|
|
rc_dbg_func("leave %p\n", ctx);
|
|
return ret;
|
}
|
|
MPP_RET rc_update_usr_cfg(RcCtx ctx, RcCfg *cfg)
|
{
|
MppRcImpl *p = (MppRcImpl *)ctx;
|
const RcImplApi *api = p->api;
|
MPP_RET ret = MPP_OK;
|
|
rc_dbg_func("enter %p\n", ctx);
|
|
p->cfg = *cfg;
|
p->fps = cfg->fps;
|
|
if (api && api->init && p->ctx)
|
api->init(p->ctx, &p->cfg);
|
|
rc_dbg_func("leave %p\n", ctx);
|
|
return ret;
|
}
|
|
MPP_RET rc_frm_check_drop(RcCtx ctx, EncRcTask *task)
|
{
|
MppRcImpl *p = (MppRcImpl *)ctx;
|
const RcImplApi *api = p->api;
|
MPP_RET ret = MPP_OK;
|
|
rc_dbg_func("enter %p\n", ctx);
|
|
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;
|
|
mpp_assert(cfg->fps_in_denorm >= 1);
|
mpp_assert(cfg->fps_out_denorm >= 1);
|
mpp_assert(rate_in >= 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;
|
|
frm_cnt += rate_out;
|
|
if (frm_cnt < rate_in)
|
drop = 1;
|
else
|
frm_cnt -= rate_in;
|
|
p->frm_cnt = frm_cnt;
|
task->frm.drop = drop;
|
}
|
|
rc_dbg_func("leave %p drop %d\n", ctx, task->frm.drop);
|
|
return ret;
|
}
|
|
MPP_RET rc_frm_check_reenc(RcCtx ctx, EncRcTask *task)
|
{
|
MppRcImpl *p = (MppRcImpl *)ctx;
|
const RcImplApi *api = p->api;
|
|
if (!api || !api->check_reenc || !p->ctx || !task)
|
return MPP_OK;
|
|
return api->check_reenc(p->ctx, task);
|
}
|
|
MPP_RET rc_frm_start(RcCtx ctx, EncRcTask *task)
|
{
|
MppRcImpl *p = (MppRcImpl *)ctx;
|
const RcImplApi *api = p->api;
|
|
if (!api || !api->frm_start || !p->ctx || !task)
|
return MPP_OK;
|
|
return api->frm_start(p->ctx, task);
|
}
|
|
MPP_RET rc_frm_end(RcCtx ctx, EncRcTask *task)
|
{
|
MppRcImpl *p = (MppRcImpl *)ctx;
|
const RcImplApi *api = p->api;
|
|
if (!api || !api->frm_end || !p->ctx || !task)
|
return MPP_OK;
|
|
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);
|
}
|