/*
 * Copyright 2017 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 __HAL_H264E_VEPU_V2_H__
#define __HAL_H264E_VEPU_V2_H__

#include "mpp_enc_cfg.h"
#include "mpp_rc.h"
#include "vepu_common.h"

#define H264E_HAL_SET_REG(reg, addr, val)                                    \
    do {                                                                     \
        reg[(addr)>>2] = (RK_U32)(val);                                      \
        if (hal_h264e_debug & 0/*H264E_HAL_LOG_INFO*/)                              \
            mpp_log("line(%d) set reg[%03d/%03x]: %08x", __LINE__, (addr)>>2, addr, val); \
    } while (0)

typedef enum H264eVpuFrameType_t {
    H264E_VPU_FRAME_P = 0,
    H264E_VPU_FRAME_I = 1
} H264eVpuFrameType;

#define VEPU_CTRL_LEVELS            7
#define VEPU_CHECK_POINTS_MAX       10

typedef struct HalH264eVepuInput_t {
    /* Hardware config format */
    RK_S32          src_fmt;
    RK_S32          src_w;
    RK_S32          src_h;

    VepuStrideCfg   stride_cfg;
    RK_S32          pixel_stride;

    size_t          size_y;
    size_t          size_c;

    RK_U32          offset_cb;
    RK_U32          offset_cr;

    RK_U8           r_mask_msb;
    RK_U8           g_mask_msb;
    RK_U8           b_mask_msb;
    RK_U8           swap_8_in;
    RK_U8           swap_16_in;
    RK_U8           swap_32_in;

    RK_U32          color_conversion_coeff_a;
    RK_U32          color_conversion_coeff_b;
    RK_U32          color_conversion_coeff_c;
    RK_U32          color_conversion_coeff_e;
    RK_U32          color_conversion_coeff_f;

    RK_U32          rotation;
} HalH264eVepuPrep;

typedef struct HalH264eVepuFrmAddr_t {
    // original frame Y/Cb/Cr/RGB address
    RK_U32          orig[3];
    // reconstruction frame
    RK_U32          recn[2];
    RK_U32          refr[2];
} HalH264eVepuAddr;

/*
 * Vepu buffer allocater
 * There are three internal buffer for Vepu encoder:
 * 1. cabac table input buffer
 * 2. nal size table output buffer
 * 3. recon / refer frame buffer
 */
typedef struct HalH264eVepuBufs_t {
    MppBufferGroup  group;

    /* cabac table buffer */
    RK_S32          cabac_init_idc;
    MppBuffer       cabac_table;

    /*
     * nal size table buffer
     * table size must be 64-bit multiple, space for zero at the end of table
     * Atleast 1 macroblock row in every slice
     */
    RK_S32          mb_h;
    RK_S32          nal_tab_size;
    MppBuffer       nal_size_table;

    /*
     * recon / refer frame buffer
     * sync with encoder using slot index
     */
    size_t          frm_size;
    size_t          yuv_size;
    RK_S32          frm_cnt;
    MppBuffer       frm_buf[H264E_MAX_REFS_CNT + 1];
} HalH264eVepuBufs;

typedef struct HalH264eVepuMbRc_t {
    /* VEPU MB rate control parameter for config to hardware */
    RK_S32          qp_init;
    RK_S32          qp_min;
    RK_S32          qp_max;

    /*
     * VEPU MB can have max 10 check points (cp).
     *
     * On each check point hardware will check the target bit and
     * error bits and change qp according to delta qp step
     *
     * cp_distance_mbs  check point distance in mbs (0 = disabled)
     * cp_target        bitrate target at each check point
     * cp_error         error bit level step for each delta qp
     * cp_delta_qp      delta qp applied on when on bit rate error amount
     */
    RK_S32          cp_distance_mbs;
    RK_S32          cp_target[VEPU_CHECK_POINTS_MAX];
    RK_S32          cp_error[VEPU_CTRL_LEVELS];
    RK_S32          cp_delta_qp[VEPU_CTRL_LEVELS];

    /*
     * MAD based QP adjustment
     * mad_qp_change    [-8..7]
     * mad_threshold    MAD threshold div256
     */
    RK_S32          mad_qp_change;
    RK_S32          mad_threshold;

    /* slice split by mb row (0 = one slice) */
    RK_S32          slice_size_mb_rows;

    /* favor and penalty for mode decision */

    /*
     * VEPU MB rate control parameter which is read from hardware
     * out_strm_size    output stream size (bits)
     * qp_sum           QP Sum div2 output
     * rlc_count        RLC codeword count div4 output max 255*255*384/4
     */
    RK_U32          hdr_strm_size;
    RK_U32          hdr_free_size;
    RK_U32          out_strm_size;
    RK_S32          qp_sum;
    RK_S32          rlc_count;

    RK_S32          cp_usage[VEPU_CHECK_POINTS_MAX];
    /* Macroblock count with MAD value under threshold output */
    RK_S32          less_mad_count;
    /* MB count output */
    RK_S32          mb_count;

    /* hardware encoding status 0 - corret 1 - error */
    RK_U32          hw_status;
} HalH264eVepuMbRc;

typedef void *HalH264eVepuMbRcCtx;



#ifdef __cplusplus
extern "C" {
#endif

RK_S32 exp_golomb_signed(RK_S32 val);

/* buffer management function */
MPP_RET h264e_vepu_buf_init(HalH264eVepuBufs *bufs);
MPP_RET h264e_vepu_buf_deinit(HalH264eVepuBufs *bufs);

MPP_RET h264e_vepu_buf_set_cabac_idc(HalH264eVepuBufs *bufs, RK_S32 idc);
MPP_RET h264e_vepu_buf_set_frame_size(HalH264eVepuBufs *bufs, RK_S32 w, RK_S32 h);

MppBuffer h264e_vepu_buf_get_nal_size_table(HalH264eVepuBufs *bufs);
MppBuffer h264e_vepu_buf_get_frame_buffer(HalH264eVepuBufs *bufs, RK_S32 index);

/* preprocess setup function */
MPP_RET h264e_vepu_prep_setup(HalH264eVepuPrep *prep, MppEncPrepCfg *cfg);
MPP_RET h264e_vepu_prep_get_addr(HalH264eVepuPrep *prep, MppBuffer buffer,
                                 RK_U32 (*addr)[3]);

/* macroblock bitrate control function */
MPP_RET h264e_vepu_mbrc_init(HalH264eVepuMbRcCtx *ctx, HalH264eVepuMbRc *mbrc);
MPP_RET h264e_vepu_mbrc_deinit(HalH264eVepuMbRcCtx ctx);

MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet *cfg);
MPP_RET h264e_vepu_slice_split_cfg(H264eSlice *slice, HalH264eVepuMbRc *mbrc,
                                   EncRcTask *rc_task, MppEncCfgSet *set_cfg);

/*
 * generate hardware MB rc config by:
 * 1 - HalH264eVepuMbRcCtx ctx
 *     The previous frame encoding status
 * 2 - RcSyntax
 *     Provide current frame target bitrate related info
 * 3 - EncFrmStatus
 *     Provide dpb related info like I / P frame, temporal id, refer distance
 *
 * Then output the HalH264eVepuMbRc for register generation
 */
MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc,
                                EncRcTask *rc_task);
MPP_RET h264e_vepu_mbrc_update(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc);

#ifdef __cplusplus
}
#endif

#endif
