blob: af0bad543569ee2f548d94f2df6ccdf80f9b6e63 [file] [log] [blame]
/*
* 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.
*/
#include "oapv_tq.h"
#include <math.h>
///////////////////////////////////////////////////////////////////////////////
// start of encoder code
#if ENABLE_ENCODER
///////////////////////////////////////////////////////////////////////////////
const int oapv_quant_scale[6] = { 26214, 23302, 20560, 18396, 16384, 14769 };
static void oapv_tx_part(s16 *src, s16 *dst, int shift, int line)
{
int j, k;
int E[4], O[4];
int EE[2], EO[2];
int add = 1 << (shift - 1);
for(j = 0; j < line; j++) {
/* E and O*/
for(k = 0; k < 4; k++) {
E[k] = src[j * 8 + k] + src[j * 8 + 7 - k];
O[k] = src[j * 8 + k] - src[j * 8 + 7 - k];
}
/* EE and EO */
EE[0] = E[0] + E[3];
EO[0] = E[0] - E[3];
EE[1] = E[1] + E[2];
EO[1] = E[1] - E[2];
dst[0 * line + j] = (oapv_tbl_tm8[0][0] * EE[0] + oapv_tbl_tm8[0][1] * EE[1] + add) >> shift;
dst[4 * line + j] = (oapv_tbl_tm8[4][0] * EE[0] + oapv_tbl_tm8[4][1] * EE[1] + add) >> shift;
dst[2 * line + j] = (oapv_tbl_tm8[2][0] * EO[0] + oapv_tbl_tm8[2][1] * EO[1] + add) >> shift;
dst[6 * line + j] = (oapv_tbl_tm8[6][0] * EO[0] + oapv_tbl_tm8[6][1] * EO[1] + add) >> shift;
dst[1 * line + j] = (oapv_tbl_tm8[1][0] * O[0] + oapv_tbl_tm8[1][1] * O[1] + oapv_tbl_tm8[1][2] * O[2] + oapv_tbl_tm8[1][3] * O[3] + add) >> shift;
dst[3 * line + j] = (oapv_tbl_tm8[3][0] * O[0] + oapv_tbl_tm8[3][1] * O[1] + oapv_tbl_tm8[3][2] * O[2] + oapv_tbl_tm8[3][3] * O[3] + add) >> shift;
dst[5 * line + j] = (oapv_tbl_tm8[5][0] * O[0] + oapv_tbl_tm8[5][1] * O[1] + oapv_tbl_tm8[5][2] * O[2] + oapv_tbl_tm8[5][3] * O[3] + add) >> shift;
dst[7 * line + j] = (oapv_tbl_tm8[7][0] * O[0] + oapv_tbl_tm8[7][1] * O[1] + oapv_tbl_tm8[7][2] * O[2] + oapv_tbl_tm8[7][3] * O[3] + add) >> shift;
}
}
const oapv_fn_tx_t oapv_tbl_fn_tx[2] = {
oapv_tx_part,
NULL
};
static __inline int get_transform_shift(int log2_size, int type, int bit_depth)
{
if(type == 0) {
return ((log2_size)-1 + bit_depth - 8);
}
else {
return ((log2_size) + 6);
}
}
void oapv_trans(oapve_ctx_t *ctx, s16 *coef, int log2_w, int log2_h, int bit_depth)
{
int shift1 = get_transform_shift(log2_w, 0, bit_depth);
int shift2 = get_transform_shift(log2_h, 1, bit_depth);
ALIGNED_16(s16 tb[OAPV_BLK_D]);
(ctx->fn_txb)[0](coef, tb, shift1, 1 << log2_h);
(ctx->fn_txb)[0](tb, coef, shift2, 1 << log2_w);
}
static int oapv_quant(s16 *coef, u8 qp, int q_matrix[OAPV_BLK_D], int log2_w, int log2_h, int bit_depth, int deadzone_offset)
{
// coef is the output of the transform, the bit range is 16
// q_matrix has the value of q_scale * 16 / q_matrix, the bit range is 19
// (precision of q_scale is 15, and the range of q_mtrix is 1~255)
// lev is the product of abs(coef) and q_matrix, the bit range is 35
s64 lev;
s32 offset;
int sign;
int i;
int shift;
int tr_shift;
int log2_size = (log2_w + log2_h) >> 1;
tr_shift = MAX_TX_DYNAMIC_RANGE - bit_depth - log2_size;
shift = QUANT_SHIFT + tr_shift + (qp / 6);
offset = deadzone_offset << (shift - 9);
int pixels = (1 << (log2_w + log2_h));
for(i = 0; i < pixels; i++) {
sign = oapv_get_sign(coef[i]);
lev = (s64)oapv_abs(coef[i]) * (q_matrix[i]);
lev = (lev + offset) >> shift;
lev = oapv_set_sign(lev, sign);
coef[i] = (s16)(oapv_clip3(-32768, 32767, lev));
}
return OAPV_OK;
}
const oapv_fn_quant_t oapv_tbl_fn_quant[2] = {
oapv_quant,
NULL
};
///////////////////////////////////////////////////////////////////////////////
// end of encoder code
#endif // ENABLE_ENCODER
///////////////////////////////////////////////////////////////////////////////
void oapv_itx_get_wo_sft(s16 *src, s16 *dst, s32 *dst32, int shift, int line)
{
int j, k;
s32 E[4], O[4];
s32 EE[2], EO[2];
int add = 1 << (shift - 1);
for(j = 0; j < line; j++) {
/* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
for(k = 0; k < 4; k++) {
O[k] = oapv_tbl_tm8[1][k] * src[1 * line + j] + oapv_tbl_tm8[3][k] * src[3 * line + j] + oapv_tbl_tm8[5][k] * src[5 * line + j] + oapv_tbl_tm8[7][k] * src[7 * line + j];
}
EO[0] = oapv_tbl_tm8[2][0] * src[2 * line + j] + oapv_tbl_tm8[6][0] * src[6 * line + j];
EO[1] = oapv_tbl_tm8[2][1] * src[2 * line + j] + oapv_tbl_tm8[6][1] * src[6 * line + j];
EE[0] = oapv_tbl_tm8[0][0] * src[0 * line + j] + oapv_tbl_tm8[4][0] * src[4 * line + j];
EE[1] = oapv_tbl_tm8[0][1] * src[0 * line + j] + oapv_tbl_tm8[4][1] * src[4 * line + j];
/* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
E[0] = EE[0] + EO[0];
E[3] = EE[0] - EO[0];
E[1] = EE[1] + EO[1];
E[2] = EE[1] - EO[1];
for(k = 0; k < 4; k++) {
dst32[j * 8 + k] = E[k] + O[k];
dst32[j * 8 + k + 4] = E[3 - k] - O[3 - k];
dst[j * 8 + k] = ((dst32[j * 8 + k] + add) >> shift);
dst[j * 8 + k + 4] = ((dst32[j * 8 + k + 4] + add) >> shift);
}
}
}
static void oapv_itx_part(s16 *src, s16 *dst, int shift, int line)
{
int j, k;
int E[4], O[4];
int EE[2], EO[2];
int add = 1 << (shift - 1);
for(j = 0; j < line; j++) {
/* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
for(k = 0; k < 4; k++) {
O[k] = oapv_tbl_tm8[1][k] * src[1 * line + j] + oapv_tbl_tm8[3][k] * src[3 * line + j] + oapv_tbl_tm8[5][k] * src[5 * line + j] + oapv_tbl_tm8[7][k] * src[7 * line + j];
}
EO[0] = oapv_tbl_tm8[2][0] * src[2 * line + j] + oapv_tbl_tm8[6][0] * src[6 * line + j];
EO[1] = oapv_tbl_tm8[2][1] * src[2 * line + j] + oapv_tbl_tm8[6][1] * src[6 * line + j];
EE[0] = oapv_tbl_tm8[0][0] * src[0 * line + j] + oapv_tbl_tm8[4][0] * src[4 * line + j];
EE[1] = oapv_tbl_tm8[0][1] * src[0 * line + j] + oapv_tbl_tm8[4][1] * src[4 * line + j];
/* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
E[0] = EE[0] + EO[0];
E[3] = EE[0] - EO[0];
E[1] = EE[1] + EO[1];
E[2] = EE[1] - EO[1];
for(k = 0; k < 4; k++) {
dst[j * 8 + k] = ((E[k] + O[k] + add) >> shift);
dst[j * 8 + k + 4] = ((E[3 - k] - O[3 - k] + add) >> shift);
}
}
}
const oapv_fn_itx_part_t oapv_tbl_fn_itx_part[2] = {
oapv_itx_part,
NULL
};
static void oapv_itx(s16 *src, int shift1, int shift2, int line)
{
ALIGNED_16(s16 dst[OAPV_BLK_D]);
oapv_itx_part(src, dst, shift1, line);
oapv_itx_part(dst, src, shift2, line);
}
const oapv_fn_itx_t oapv_tbl_fn_itx[2] = {
oapv_itx,
NULL
};
static void oapv_dquant(s16 *coef, s16 q_matrix[OAPV_BLK_D], int log2_w, int log2_h, s8 shift)
{
int i;
int lev;
int pixels = (1 << (log2_w + log2_h));
if(shift > 0) {
s32 offset = (1 << (shift - 1));
for(i = 0; i < pixels; i++) {
lev = (coef[i] * q_matrix[i] + offset) >> shift;
coef[i] = (s16)oapv_clip3(-32768, 32767, lev);
}
}
else {
int left_shift = -shift;
for(i = 0; i < pixels; i++) {
lev = (coef[i] * q_matrix[i]) << left_shift;
coef[i] = (s16)oapv_clip3(-32768, 32767, lev);
}
}
}
const oapv_fn_dquant_t oapv_tbl_fn_dquant[2] = {
oapv_dquant,
NULL
};
void oapv_adjust_itrans(int *src, int *dst, int itrans_diff_idx, int diff_step, int shift)
{
int offset = 1 << (shift - 1);
for(int k = 0; k < 64; k++) {
dst[k] = src[k] + ((oapv_itrans_diff[itrans_diff_idx][k] * diff_step + offset) >> shift);
}
}
const oapv_fn_itx_adj_t oapv_tbl_fn_itx_adj[2] = {
oapv_adjust_itrans,
NULL,
};