/*
 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
 * All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * - Neither the name of the copyright owner, nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _OAPV_DEF_H_4738294732894739280473892473829_
#define _OAPV_DEF_H_4738294732894739280473892473829_

#ifndef ENABLE_ENCODER
#define ENABLE_ENCODER 1 // for enabling encoder functionality
#endif

#ifndef ENABLE_DECODER
#define ENABLE_DECODER 1 // for enabling decoder functionality
#endif

#include "oapv.h"
#include "oapv_port.h"
#include "oapv_bs.h"
#include "oapv_tpool.h"

/* oapv encoder magic code */
#define OAPVE_MAGIC_CODE          0x41503145 /* AP1E */

/* oapv decoder magic code */
#define OAPVD_MAGIC_CODE          0x41503144 /* AP1D */

/* Max. and min. Quantization parameter */
#define MAX_QUANT(BD)             (63 + ((BD-10)*6))
#define MIN_QUANT                 0

#define MAX_COST                  (1.7e+308) /* maximum cost value */

#define Y_C                       0 /* Y luma */
#define U_C                       1 /* Cb Chroma */
#define V_C                       2 /* Cr Chroma */
#define X_C                       3 /* X channel */
#define N_C                       4 /* maximum number of color component */

#define OAPV_VLC_TREE_LEVEL       2
#define OAPV_KPARAM_DC_MIN        0
#define OAPV_KPARAM_DC_MAX        5
#define OAPV_KPARAM_AC_MIN        0
#define OAPV_KPARAM_AC_MAX        4
#define OAPV_KPARAM_RUN_MIN       0
#define OAPV_KPARAM_RUN_MAX       2

/* Maximum transform dynamic range (excluding sign bit) */
#define MAX_TX_DYNAMIC_RANGE      15
#define MAX_TX_VAL                ((1 << MAX_TX_DYNAMIC_RANGE) - 1)
#define MIN_TX_VAL                (-(1 << MAX_TX_DYNAMIC_RANGE))

#define QUANT_SHIFT               14
#define QUANT_DQUANT_SHIFT        20

/* encoder status */
#define ENC_TILE_STAT_NOT_ENCODED 0
#define ENC_TILE_STAT_ON_ENCODING 1
#define ENC_TILE_STAT_ENCODED     2

/*****************************************************************************
 * PBU data structure
 *****************************************************************************/
typedef struct oapv_pbuh oapv_pbuh_t;
struct oapv_pbuh { // 4-byte
    int pbu_type;  /* u( 8) */
    int group_id;  /* u(16) */
    // int reserved_zero_8bits                    /* u( 8) */
};

/*****************************************************************************
 * Frame info
 *****************************************************************************/
typedef struct oapv_fi oapv_fi_t;
struct oapv_fi {     // 112byte
    int profile_idc; /* u( 8) */
    int level_idc;   /* u( 8) */
    int band_idc;    /* u( 3) */
    // int            reserved_zero_5bits;                     /* u( 5) */
    u32 frame_width;           /* u(24) */
    u32 frame_height;          /* u(24) */
    int chroma_format_idc;     /* u( 4) */
    int bit_depth;             /* u( 4) */
    int capture_time_distance; /* u( 8) */
    // int            reserved_zero_8bits;                     /* u( 8) */
};

/*****************************************************************************
 * Frame header
 *****************************************************************************/
typedef struct oapv_fh oapv_fh_t;
struct oapv_fh {
    oapv_fi_t fi;
    // int reserved_zero_8bits_3;                 /* u( 8) */
    int       color_description_present_flag; /* u( 1) */
    int       color_primaries;                /* u( 8) */
    int       transfer_characteristics;       /* u( 8) */
    int       matrix_coefficients;            /* u( 8) */
    int       full_range_flag;                /* u( 1) */
    int       use_q_matrix;                   /* u( 1) */
    /* (start) quantization_matrix  */
    int       q_matrix[N_C][OAPV_BLK_H][OAPV_BLK_W]; /* u( 8) */
    /* ( end ) quantization_matrix  */
    /* (start) tile_info */
    int       tile_width_in_mbs;            /* u(20) */
    int       tile_height_in_mbs;           /* u(20) */
    int       tile_size_present_in_fh_flag; /* u( 1) */
    u32       tile_size[OAPV_MAX_TILES];    /* u(32) */
    /* ( end ) tile_info  */
    // int reserved_zero_8bits_4;                   /* u( 8) */
};

/*****************************************************************************
 * Tile header
 *****************************************************************************/
#define OAPV_TILE_SIZE_LEN 4 /* u(32), 4byte */
typedef struct oapv_th oapv_th_t;
struct oapv_th {
    int tile_header_size;    /* u(16) */
    int tile_index;          /* u(16) */
    u32 tile_data_size[N_C]; /* u(32) */
    int tile_qp[N_C];        /* u( 8) */
    int reserved_zero_8bits; /* u( 8) */
};

/*****************************************************************************
 * Access unit info
 *****************************************************************************/
typedef struct oapv_aui oapv_aui_t;
struct oapv_aui {
    int       num_frames;                    // u(16)
    int       pbu_type[OAPV_MAX_NUM_FRAMES]; // u(8)
    int       group_id[OAPV_MAX_NUM_FRAMES]; // u(16)
    // int reserved_zero_8bits[OAPV_MAX_NUM_FRAMES]; // u(8)
    oapv_fi_t frame_info[OAPV_MAX_NUM_FRAMES];
    // int reserved_zero_8bits // u(8)
};

///////////////////////////////////////////////////////////////////////////////
// start of encoder code
#if ENABLE_ENCODER
///////////////////////////////////////////////////////////////////////////////
/*****************************************************************************
 * pre-declaration
 *****************************************************************************/
typedef struct oapve_ctx  oapve_ctx_t;
typedef struct oapve_core oapve_core_t;

/*****************************************************************************
 * pre-defined function structure
 *****************************************************************************/
typedef void (*oapv_fn_itx_part_t)(s16 *coef, s16 *t, int shift, int line);
typedef void (*oapv_fn_itx_t)(s16 *coef, int shift1, int shift2, int line);
typedef void (*oapv_fn_tx_t)(s16 *coef, int shift1, int shift2, int line);
typedef void (*oapv_fn_itx_adj_t)(int *src, int *dst, int itrans_diff_idx, int diff_step, int shift);
typedef int (*oapv_fn_quant_t)(s16 *coef, u8 qp, int q_matrix[OAPV_BLK_D], int log2_w, int log2_h, int bit_depth, int deadzone_offset);
typedef void (*oapv_fn_dquant_t)(s16 *coef, s16 q_matrix[OAPV_BLK_D], int log2_w, int log2_h, s8 shift);
typedef int (*oapv_fn_sad_t)(int w, int h, void *src1, void *src2, int s_src1, int s_src2);
typedef s64 (*oapv_fn_ssd_t)(int w, int h, void *src1, void *src2, int s_src1, int s_src2);
typedef void (*oapv_fn_diff_t)(int w, int h, void *src1, void *src2, int s_src1, int s_src2, int s_diff, s16 *diff);

typedef double (*oapv_fn_enc_blk_cost_t)(oapve_ctx_t *ctx, oapve_core_t *core, int log2_w, int log2_h, int c);
typedef void (*oapv_fn_imgb_to_blk_rc_t)(oapv_imgb_t *imgb, int c, int x_l, int y_l, int w_l, int h_l, s16 *block, int bit_depth);
typedef void (*oapv_fn_imgb_to_blk_t)(void *src, int blk_w, int blk_h, int s_src, int offset_src, int s_dst, void *dst, int bit_depth);
typedef void (*oapv_fn_blk_to_imgb_t)(void *src, int blk_w, int blk_h, int s_src, int offset_dst, int s_dst, void *dst, int bit_depth);
typedef void (*oapv_fn_imgb_pad_t)(oapv_imgb_t *imgb, int aw, int ah, int comp_sft[N_C][2]);
typedef int (*oapv_fn_had8x8_t)(pel *org, int s_org);

/*****************************************************************************
 * rate-control related
 *****************************************************************************/
typedef struct oapve_rc_param {
    double alpha;
    double beta;

    int    qp;
    double lambda;
    double cost;
    unsigned char is_updated;
} oapve_rc_param_t;

typedef struct oapve_rc_tile {
    int              qp;
    int              target_bits;
    double           lambda;
    int              number_pixel;
    double           cost;
    int              target_bits_left;

    u64              total_dist;
    oapve_rc_param_t rc_param;
} oapve_rc_tile_t;

/*****************************************************************************
 * CORE information used for encoding process.
 *
 * The variables in this structure are very often used in encoding process.
 *****************************************************************************/
struct oapve_core {
    ALIGNED_16(s16 coef[OAPV_BLK_D]);
    ALIGNED_16(s16 coef_rec[OAPV_BLK_D]);

    int          kparam_dc[N_C];
    int          kparam_ac[N_C];
    int          prev_dc[N_C];

    int          tile_idx;

    int          dc_diff; /* DC difference, which is represented in 17 bits */
                          /* and coded as abs_dc_coeff_diff and sign_dc_coeff_diff */
    int          qp[N_C]; // QPs for Y, Cb(U), Cr(V)
    int          dq_shift[N_C];

    int          q_mat_enc[N_C][OAPV_BLK_D];
    s16          q_mat_dec[N_C][OAPV_BLK_D];
    double       err_scale_tbl[N_C][OAPV_BLK_D];
    int          thread_idx;

    oapve_ctx_t *ctx;
    /* platform specific data, if needed */
    void        *pf;
};

typedef struct oapve_tile oapve_tile_t;
struct oapve_tile {
    oapv_th_t       th;

    int             x; /* x (column) position in a frame in unit of pixel */
    int             y; /* y (row) position in a frame in unit of pixel */
    int             w; /* tile width in unit of pixel */
    int             h; /* tile height in unit of pixel */
    u32             tile_size;
    oapve_rc_tile_t rc;
    u8             *bs_buf;
    s32             bs_size;
    u32             bs_buf_max;
    volatile s32    stat;
};

/******************************************************************************
 * CONTEXT used for encoding process.
 *
 * All have to be stored are in this structure.
 *****************************************************************************/
struct oapve_ctx {
    u32                       magic; // magic code
    oapve_t                   id;    // identifier
    oapve_cdesc_t             cdesc;
    oapv_imgb_t              *imgb_i;
    oapv_imgb_t              *imgb_r;

    oapve_param_t            *param;
    oapv_fh_t                 fh;
    oapve_tile_t              tile[OAPV_MAX_TILES];
    int                       num_tiles_frms[OAPV_MAX_NUM_FRAMES];
    int                       num_tiles;
    int                       num_tile_cols;
    int                       num_tile_rows;
    int                       qp[N_C];
    s8                        qp_offset[N_C];
    int                       w;
    int                       h;
    int                       cfi;
    int                       num_comp;
    int                       bit_depth;
    int                       comp_sft[N_C][2];
    oapv_tpool_t             *tpool;
    oapv_thread_t             thread_id[OAPV_MAX_THREADS];
    oapv_sync_obj_t           sync_obj;
    oapve_core_t             *core[OAPV_MAX_THREADS];

    const oapv_fn_itx_part_t *fn_itx_part;
    const oapv_fn_itx_t      *fn_itx;
    const oapv_fn_itx_adj_t  *fn_itx_adj;
    const oapv_fn_tx_t       *fn_txb;
    const oapv_fn_quant_t    *fn_quant;
    const oapv_fn_dquant_t   *fn_dquant;
    const oapv_fn_sad_t      *fn_sad;
    const oapv_fn_ssd_t      *fn_ssd;
    const oapv_fn_diff_t     *fn_diff;
    oapv_fn_imgb_to_blk_rc_t  fn_imgb_to_blk_rc;
    oapv_fn_imgb_to_blk_t     fn_imgb_to_blk[N_C];
    oapv_fn_blk_to_imgb_t     fn_blk_to_imgb[N_C];
    oapv_fn_imgb_pad_t        fn_imgb_pad;
    oapv_fn_enc_blk_cost_t    fn_enc_blk;
    oapv_fn_had8x8_t          fn_had8x8;

    int                       use_frm_hash;
    oapve_rc_param_t          rc_param;

    int                       threads; // num of thread for encoding
    int                       au_bs_fmt; // access unit bitstream format
    /* platform specific data, if needed */
    void                     *pf;
};
///////////////////////////////////////////////////////////////////////////////
// end of encoder code
#endif // ENABLE_ENCODER
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// start of decoder code
#if ENABLE_DECODER
///////////////////////////////////////////////////////////////////////////////
#define DEC_TILE_STAT_NOT_DECODED 0
#define DEC_TILE_STAT_ON_DECODING 1
#define DEC_TILE_STAT_DECODED     2
#define DEC_TILE_STAT_SIZE_ERROR  -1

typedef struct oapvd_tile oapvd_tile_t;
struct oapvd_tile {
    oapv_th_t    th;

    int          x;         /* x (column) position in a frame in unit of pixel */
    int          y;         /* y (row) position in a frame in unit of pixel */
    int          w;         /* tile width in unit of pixel */
    int          h;         /* tile height in unit of pixel */
    u32          data_size; /* tile size including tile_size syntax */

    u8          *bs_beg; /* start position of tile in input bistream */
    u8          *bs_end; /* end position of tile() in input bistream */
    volatile s32 stat;   // decoding status
};

typedef struct oapvd_core oapvd_core_t;
typedef struct oapvd_ctx  oapvd_ctx_t;

struct oapvd_core {
    ALIGNED_16(s16 coef[OAPV_MB_D]);
    s16          q_mat[N_C][OAPV_BLK_D];

    int          kparam_dc[N_C];
    int          kparam_ac[N_C];
    int          prev_dc[N_C];
    int          dc_diff; /* DC difference, which is represented in 17 bits */
                          /* and coded as abs_dc_coeff_diff and sign_dc_coeff_diff */
    int          qp[N_C];
    int          dq_shift[N_C];
    int          tile_idx;

    oapvd_ctx_t *ctx;
    /* platform specific data, if needed */
    void        *pf;
};

struct oapvd_ctx {
    u32                     magic; // magic code
    oapvd_t                 id;    // identifier

    oapvd_cdesc_t           cdesc;
    oapvd_core_t           *core[OAPV_MAX_THREADS];
    oapv_imgb_t            *imgb;
    const oapv_fn_itx_t    *fn_itx;
    const oapv_fn_dquant_t *fn_dquant;
    oapv_fn_blk_to_imgb_t   fn_block_to_imgb[N_C];
    oapv_bs_t               bs;

    oapv_fh_t               fh;
    oapvd_tile_t            tile[OAPV_MAX_TILES];

    u8                     *tile_end;
    int                     num_tiles;
    int                     num_tile_cols;
    int                     num_tile_rows;
    int                     w;
    int                     h;
    int                     threads;
    oapv_tpool_t           *tpool;
    oapv_thread_t           thread_id[OAPV_MAX_THREADS];
    oapv_sync_obj_t         sync_obj;
    int                     cfi;              // chroma format indicator
    int                     bit_depth;        // bit depth of decoding picture
    int                     num_comp;         // number of components
    int                     comp_sft[N_C][2]; // width or height shift value of each compoents, 0: width, 1: height
    int                     use_frm_hash;

    /* platform specific data, if needed */
    void                   *pf;
};
///////////////////////////////////////////////////////////////////////////////
// end of decoder code
#endif // ENABLE_DECODER
///////////////////////////////////////////////////////////////////////////////

#define OAPV_FRAME_INFO_BYTE (112)
#define OAPV_PBU_HEADER_BYTE (32)

#include "oapv_metadata.h"
#include "oapv_vlc.h"
#include "oapv_tq.h"
#include "oapv_util.h"
#include "oapv_tbl.h"
#include "oapv_rc.h"
#include "oapv_sad.h"
#include "oapv_param.h"

#if X86_SSE
#include "sse/oapv_sad_sse.h"
#include "sse/oapv_tq_sse.h"
#include "avx/oapv_sad_avx.h"
#include "avx/oapv_tq_avx.h"
#elif ARM_NEON
#include "neon/oapv_sad_neon.h"
#include "neon/oapv_tq_neon.h"
#endif

#endif /* _OAPV_DEF_H_4738294732894739280473892473829_ */
