/*
 * 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  "vp8e_api_v2"

#include <string.h>
#include <limits.h>

#include "mpp_env.h"
#include "mpp_mem.h"
#include "mpp_debug.h"
#include "mpp_common.h"
#include "mpp_rc.h"
#include "mpp_enc_cfg.h"

#include "vp8e_api_v2.h"
#include "vp8e_syntax.h"

#define VP8E_DBG_FUNCTION            (0x00000001)
#define VP8E_DBG_CFG                 (0x00000002)

#define vp8e_dbg_cfg(fmt, ...)    _mpp_dbg_f(vp8e_debug, VP8E_DBG_CFG, fmt, ## __VA_ARGS__)
#define vp8e_dbg_fun(fmt, ...)    _mpp_dbg_f(vp8e_debug, VP8E_DBG_FUNCTION, fmt, ## __VA_ARGS__)

RK_U32 vp8e_debug = 0;
#define VP8E_SYN_BUTT 2

typedef struct {
    /* config from mpp_enc */
    MppEncCfgSet    *cfg;

    /* internal rate control config*/
    Vp8eRc          *rc;

    Vp8eSyntax      vp8e_syntax[VP8E_SYN_BUTT];
} Vp8eCtx;

static MPP_RET vp8e_init(void *ctx, EncImplCfg *ctrl_cfg)
{
    MPP_RET ret = MPP_OK;
    Vp8eCtx *p = (Vp8eCtx *)ctx;

    MppEncRcCfg *rc_cfg = &ctrl_cfg->cfg->rc;
    MppEncPrepCfg *prep = &ctrl_cfg->cfg->prep;

    vp8e_dbg_fun("enter\n");
    if (NULL == ctx || NULL == ctrl_cfg) {
        mpp_err_f("Init failed, contex or controller cfg is null!\n");
        ret = MPP_NOK;
        goto __ERR_RET;
    }

    p->cfg = ctrl_cfg->cfg;

    /*
     * default prep:
     * 720p
     * YUV420SP
     */
    prep->width = 1280;
    prep->height = 720;
    prep->hor_stride = 1280;
    prep->ver_stride = 720;
    prep->format = MPP_FMT_YUV420SP;
    prep->rotation = MPP_ENC_ROT_0;
    prep->rotation_ext = MPP_ENC_ROT_0;
    prep->mirroring = 0;
    prep->mirroring_ext = 0;
    prep->denoise = 0;

    /*
     * default rc_cfg:
     * CBR
     * 2Mbps +-25%
     * 30fps
     * gop 60
     */
    rc_cfg->rc_mode = MPP_ENC_RC_MODE_CBR;
    rc_cfg->quality = MPP_ENC_RC_QUALITY_MEDIUM;
    rc_cfg->bps_target = 2000 * 1000;
    rc_cfg->bps_max = rc_cfg->bps_target * 5 / 4;
    rc_cfg->bps_min = rc_cfg->bps_target * 3 / 4;
    rc_cfg->fps_in_flex = 0;
    rc_cfg->fps_in_num = 30;
    rc_cfg->fps_in_denom = 1;
    rc_cfg->fps_out_flex = 0;
    rc_cfg->fps_out_num = 30;
    rc_cfg->fps_out_denom = 1;
    rc_cfg->gop = 60;
    rc_cfg->max_reenc_times = 1;
    rc_cfg->fqp_min_i = INT_MAX;
    rc_cfg->fqp_min_p = INT_MAX;
    rc_cfg->fqp_max_i = INT_MAX;
    rc_cfg->fqp_max_p = INT_MAX;

    p->rc = mpp_calloc(Vp8eRc, 1);
    memset(p->rc, 0, sizeof(Vp8eRc));
    p->rc->frame_coded = 1;
    if (NULL == p->rc) {
        mpp_err_f("failed to malloc vp8_rc\n");
        ret = MPP_ERR_MALLOC;
        goto __ERR_RET;
    }

    mpp_env_get_u32("vp8e_debug", &vp8e_debug, 0);

    vp8e_dbg_fun("leave ret %d\n", ret);
    return ret;

__ERR_RET:
    vp8e_dbg_fun("leave ret %d\n", ret);
    return ret;
}

static MPP_RET vp8e_deinit(void *ctx)
{
    Vp8eCtx *p = (Vp8eCtx *)ctx;

    vp8e_dbg_fun("enter\n");

    if (p->rc)
        mpp_free(p->rc);

    vp8e_dbg_fun("leave\n");
    return MPP_OK;
}

static MPP_RET vp8e_start(void *ctx, HalEncTask *task)
{
    (void)ctx;
    (void)task;

    return MPP_OK;
}

static MPP_RET vp8e_proc_dpb(void *ctx, HalEncTask *task)
{
    (void)ctx;
    EncRcTask    *rc_task = task->rc_task;
    EncCpbStatus *cpb = &task->rc_task->cpb;
    rc_task->frm.val = cpb->curr.val;
    return MPP_OK;
}

static MPP_RET vp8e_proc_cfg(void *ctx, MpiCmd cmd, void *param)
{
    MPP_RET ret = MPP_OK;

    vp8e_dbg_fun("enter ctx %p cmd %x param %p\n", ctx, cmd, param);
    switch (cmd) {
    case MPP_ENC_SET_CFG : {
    } break;
    default: {
        mpp_err("No correspond cmd found, and can not config!");
        ret = MPP_NOK;
    } break;
    }

    vp8e_dbg_fun("leave ret %d\n", ret);
    return ret;
}

static MPP_RET vp8e_proc_hal(void *ctx, HalEncTask *task)
{
    Vp8eCtx *p = (Vp8eCtx *)ctx;
    Vp8eSyntax *syntax = &p->vp8e_syntax[0];
    RK_U32 syn_num = 0;

    syntax[syn_num].type = VP8E_SYN_CFG;
    syntax[syn_num].data = p->cfg;
    syn_num++;
    syntax[syn_num].type = VP8E_SYN_RC;
    syntax[syn_num].data = p->rc;
    syn_num++;
    task->syntax.data = syntax;
    task->syntax.number = syn_num;

    task->valid = 1;
    return MPP_OK;
}

const EncImplApi api_vp8e = {
    .name       = "vp8_control",
    .coding     = MPP_VIDEO_CodingVP8,
    .ctx_size   = sizeof(Vp8eCtx),
    .flag       = 0,
    .init       = vp8e_init,
    .deinit     = vp8e_deinit,
    .proc_cfg   = vp8e_proc_cfg,
    .gen_hdr    = NULL,
    .start      = vp8e_start,
    .proc_dpb   = vp8e_proc_dpb,
    .proc_hal   = vp8e_proc_hal,
    .add_prefix = NULL,
    .sw_enc     = NULL,
};
