[transform-skip] Bitstream generation for transform-skip

This commit is contained in:
Joose Sainio 2021-04-27 14:13:44 +03:00
parent 0cc1bf197f
commit 7ff904fd9d
6 changed files with 409 additions and 22 deletions

View file

@ -96,6 +96,15 @@ typedef struct
cabac_ctx_t multi_ref_line[2];
cabac_ctx_t bdpcm_mode[4];
cabac_ctx_t joint_bc_br[3];
cabac_ctx_t transform_skip_model_luma;
cabac_ctx_t transform_skip_model_chroma;
cabac_ctx_t transform_skip_sig_coeff[3];
cabac_ctx_t transform_skip_sig[3];
cabac_ctx_t transform_skip_res_sign[6];
cabac_ctx_t transform_skip_gt1[4];
cabac_ctx_t transform_skip_par;
cabac_ctx_t transform_skip_gt2[5];
} ctx;
} cabac_data_t;

View file

@ -314,6 +314,61 @@ static const uint8_t INIT_CU_TRANSQUANT_BYPASS[4][1] = {
{ DWS, },
};
static const uint8_t INIT_TRANSFORM_SKIP[4][2] = {
{ 25, 17, },
{ 25, 9, },
{ 25, 9, },
{ 1, 1, },
};
static const uint8_t INIT_TRANSFORM_SKIP_SIG_COEFF[4][3] =
{
{ 18, 35, 45, },
{ 18, 12, 29, },
{ 18, 20, 38, },
{ 5, 8, 8, },
};
static const uint8_t INIT_TRANSFORM_SKIP_SIG[4][3] =
{
{ 25, 50, 37, },
{ 40, 35, 44, },
{ 25, 28, 38, },
{ 13, 13, 8, },
};
static const uint8_t INIT_TRANSFORM_SKIP_PARITY[4][1] =
{
{ 11, },
{ 3, },
{ 11, },
{ 6, },
};
static const uint8_t INIT_TRANSFORM_SKIP_GT2[4][5] =
{
{ CNU, 3, 4, 4, 5, },
{ CNU, 2, 10, 3, 3, },
{ CNU, 10, 3, 3, 3, },
{ DWS, 1, 1, 1, 1, },
};
static const uint8_t INIT_TRANSFORM_SKIP_GT1[4][4] =
{
{ 19, 11, 4, 6, },
{ 18, 11, 4, 28, },
{ 11, 5, 5, 14, },
{ 4, 2, 1, 6, },
};
static const uint8_t INIT_TRANSFORM_SKIP_RES_SIGN[4][6] =
{
{ 35, 25, 46, 28, 33, 38, },
{ 5, 10, 53, 43, 25, 46, },
{ 12, 17, 46, 28, 25, 46, },
{ 1, 4, 4, 5, 8, 8, },
};
static const uint8_t INIT_INTRA_SUBPART_MODE[4][2] = {
{ 33, 43, },
{ 33, 36, },
@ -387,7 +442,10 @@ void kvz_init_contexts(encoder_state_t *state, int8_t QP, int8_t slice)
kvz_ctx_init(&cabac->ctx.intra_subpart_model[0], QP, INIT_INTRA_SUBPART_MODE[slice][0], INIT_INTRA_SUBPART_MODE[3][0]);
kvz_ctx_init(&cabac->ctx.intra_subpart_model[1], QP, INIT_INTRA_SUBPART_MODE[slice][1], INIT_INTRA_SUBPART_MODE[3][1]);
kvz_ctx_init(&cabac->ctx.transform_skip_model_luma, QP, INIT_TRANSFORM_SKIP[slice][0], INIT_TRANSFORM_SKIP[3][0]);
kvz_ctx_init(&cabac->ctx.transform_skip_model_chroma, QP, INIT_TRANSFORM_SKIP[slice][1], INIT_TRANSFORM_SKIP[3][1]);
kvz_ctx_init(&cabac->ctx.transform_skip_par, QP, INIT_TRANSFORM_SKIP_PARITY[slice][0], INIT_TRANSFORM_SKIP_PARITY[3][0]);
kvz_ctx_init(&cabac->ctx.multi_ref_line[0], QP, MULTI_REF_LINE_MODE[slice][0], MULTI_REF_LINE_MODE[3][0]);
kvz_ctx_init(&cabac->ctx.multi_ref_line[1], QP, MULTI_REF_LINE_MODE[slice][1], MULTI_REF_LINE_MODE[3][1]);
@ -398,21 +456,26 @@ void kvz_init_contexts(encoder_state_t *state, int8_t QP, int8_t slice)
for (i = 0; i < 3; i++) {
kvz_ctx_init(&cabac->ctx.cu_skip_flag_model[i], QP, INIT_SKIP_FLAG[slice][i], INIT_SKIP_FLAG[3][i]);
kvz_ctx_init(&cabac->ctx.joint_bc_br[i], QP, INIT_JOINT_CB_CR_FLAG[slice][i], INIT_JOINT_CB_CR_FLAG[3][i]);
kvz_ctx_init(&cabac->ctx.transform_skip_sig_coeff[i], QP, INIT_TRANSFORM_SKIP_SIG_COEFF[slice][i], INIT_TRANSFORM_SKIP_SIG_COEFF[3][i]);
kvz_ctx_init(&cabac->ctx.transform_skip_sig[i], QP, INIT_TRANSFORM_SKIP_SIG[slice][i], INIT_TRANSFORM_SKIP_SIG[3][i]);
}
for (i = 0; i < 4; i++) {
kvz_ctx_init(&cabac->ctx.sig_coeff_group_model[i], QP, INIT_SIG_COEFF_GROUP[slice][i], INIT_SIG_COEFF_GROUP[3][i]);
kvz_ctx_init(&cabac->ctx.mts_idx_model[i], QP, INIT_MTS_IDX[slice][i], INIT_MTS_IDX[3][i]);
kvz_ctx_init(&cabac->ctx.transform_skip_gt1[i], QP, INIT_TRANSFORM_SKIP_GT1[slice][i], INIT_TRANSFORM_SKIP_GT1[3][i]);
}
for (i = 0; i < 5; i++) {
kvz_ctx_init(&cabac->ctx.transform_skip_gt2[i], QP, INIT_TRANSFORM_SKIP_GT2[slice][i], INIT_TRANSFORM_SKIP_GT2[3][i]);
}
for (i = 0; i < 6; i++) {
kvz_ctx_init(&cabac->ctx.qt_split_flag_model[i], QP, INIT_QT_SPLIT_FLAG[slice][i], INIT_QT_SPLIT_FLAG[3][i]);
kvz_ctx_init(&cabac->ctx.alf_cc_filter_control_flag[i], QP, INIT_CC_ALF_FILTER_CONTROL_FLAG[slice][i], INIT_CC_ALF_FILTER_CONTROL_FLAG[3][i]);
kvz_ctx_init(&cabac->ctx.transform_skip_res_sign[i], QP, INIT_TRANSFORM_SKIP_RES_SIGN[slice][i], INIT_TRANSFORM_SKIP_RES_SIGN[3][i]);
}
for (i = 0; i < 9; i++) {
kvz_ctx_init(&cabac->ctx.split_flag_model[i], QP, INIT_SPLIT_FLAG[slice][i], INIT_SPLIT_FLAG[3][i]);
kvz_ctx_init(&cabac->ctx.alf_ctb_flag_model[i], QP, INIT_CTB_ALF_FLAG[slice][i], INIT_CTB_ALF_FLAG[3][i]);
@ -555,6 +618,114 @@ uint32_t kvz_context_get_sig_ctx_idx_abs(const coeff_t* coeff, int32_t pos_x, in
return ctx_ofs;
}
uint32_t kvz_context_get_sig_ctx_idx_abs_ts(const coeff_t* coeff, int32_t pos_x, int32_t pos_y, uint32_t width)
{
const coeff_t* data = coeff + pos_x + pos_y * width;
int numPos = 0;
#define UPDATE(x) {coeff_t a=abs(x);numPos+=!!a;}
if (pos_x > 0)
{
UPDATE(data[-1]);
}
if (pos_y > 0)
{
UPDATE(data[-(int)width]);
}
#undef UPDATE
return numPos;
}
uint32_t kvz_sign_ctx_id_abs_ts(const coeff_t* coeff, int32_t pos_x, int32_t pos_y, int32_t width, int bdpcm)
{
const coeff_t* pData = coeff + pos_x + pos_y * width;
int rightSign = 0, belowSign = 0;
unsigned signCtx = 0;
#define SGN(val) ((0 < (val)) - ((val) < 0))
if (pos_x > 0)
{
rightSign = SGN(pData[-1]);
}
if (pos_y > 0)
{
belowSign = SGN(pData[-(int)width]);
}
#undef SGN
if ((rightSign == 0 && belowSign == 0) || ((rightSign * belowSign) < 0))
{
signCtx = 0;
}
else if (rightSign >= 0 && belowSign >= 0)
{
signCtx = 1;
}
else
{
signCtx = 2;
}
if (bdpcm)
{
signCtx += 3;
}
return signCtx;
}
int32_t kvz_derive_mod_coeff(int rightPixel, int belowPixel, coeff_t absCoeff, int bdpcm)
{
if (absCoeff == 0)
return 0;
int pred1, absBelow = abs(belowPixel), absRight = abs(rightPixel);
int absCoeffMod = absCoeff;
if (bdpcm == 0)
{
pred1 = MAX(absBelow, absRight);
if (absCoeffMod == pred1)
{
absCoeffMod = 1;
}
else
{
absCoeffMod = absCoeffMod < pred1 ? absCoeffMod + 1 : absCoeffMod;
}
}
return(absCoeffMod);
}
unsigned kvz_lrg1_ctx_id_abs_ts(const coeff_t* coeff, int32_t pos_x, int32_t pos_y, int32_t width, int bdpcm)
{
const coeff_t* posC = coeff + pos_x + pos_y * width;
int numPos = 0;
#define UPDATE(x) {coeff_t a=abs(x);numPos+=!!a;}
if (bdpcm)
{
numPos = 3;
}
else
{
if (pos_x > 0)
{
UPDATE(posC[-1]);
}
if (pos_y > 0)
{
UPDATE(posC[-width]);
}
}
#undef UPDATE
return numPos;
}
/**
* \brief Calculate slot of Go rice parameter for remainder coefficient value coding
* \param coeff pointer to the current coefficient

View file

@ -43,6 +43,13 @@ uint32_t kvz_context_get_sig_ctx_idx_abs(const coeff_t* coeff, int32_t pos_x, in
uint32_t height, uint32_t width, int8_t type,
int32_t* temp_diag, int32_t* temp_sum);
uint32_t kvz_context_get_sig_ctx_idx_abs_ts(const coeff_t* coeff, int32_t pos_x, int32_t pos_y,
uint32_t width);
uint32_t kvz_sign_ctx_id_abs_ts(const coeff_t* coeff, int32_t pos_x, int32_t pos_y, int32_t width, int bdpcm);
int32_t kvz_derive_mod_coeff(int rightPixel, int belowPixel, coeff_t absCoeff, int bdpcm);
unsigned kvz_lrg1_ctx_id_abs_ts(const coeff_t* coeff, int32_t pos_x, int32_t pos_y, int32_t width, int bdpcm);
uint32_t kvz_abs_sum(const coeff_t* coeff, int32_t pos_x, int32_t pos_y,
uint32_t height, uint32_t width, uint32_t baselevel);

View file

@ -89,6 +89,176 @@ static void encode_mts_idx(encoder_state_t * const state,
}
}
static void encode_ts_residual(encoder_state_t* const state,
cabac_data_t* const cabac,
const coeff_t* coeff,
uint8_t width,
uint8_t type,
int8_t scan_mode) {
//const encoder_control_t * const encoder = state->encoder_control;
//int c1 = 1;
int32_t i;
int32_t blk_pos;
// ToDo: large block support in VVC?
uint32_t sig_coeffgroup_flag[32 * 32] = { 0 };
// CONSTANTS
const uint32_t log2_block_size = kvz_g_convert_to_bit[width] + 2;
const uint32_t log2_cg_size = kvz_g_log2_sbb_size[log2_block_size][log2_block_size][0] + kvz_g_log2_sbb_size[log2_block_size][log2_block_size][1];
const uint32_t* scan =
kvz_g_sig_last_scan[scan_mode][log2_block_size - 1];
const uint32_t* scan_cg = g_sig_last_scan_cg[log2_block_size - 1][scan_mode];
// Init base contexts according to block type
cabac_ctx_t* base_coeff_group_ctx = &(cabac->ctx.sig_coeff_group_model[(type == 0 ? 0 : 1) * 2 + 1]);
cabac->cur_ctx = base_coeff_group_ctx;
int maxCtxBins = (width * width * 7) >> 2;
unsigned scan_cg_last = -1;
unsigned scan_pos_last = -1;
for (int i = 0; i < width * width; i++) {
if (coeff[scan[i]]) {
scan_pos_last = i;
sig_coeffgroup_flag[scan_cg[i >> log2_cg_size]] = 1;
}
}
scan_cg_last = scan_pos_last >> log2_cg_size;
for (i = 0; i <= (width * width - 1) >> log2_cg_size; i++) {
if (!(i == 0 || i ==scan_cg_last)) {
if(!sig_coeffgroup_flag[scan_cg[i]]) {
CABAC_BIN(cabac, 0, "sb_coded_flag");
continue;
}
CABAC_BIN(cabac, 1, "sb_coded_flag");
}
int firstSigPos = i << log2_cg_size;
int min_sub_pos = firstSigPos + (1 << log2_cg_size) - 1;
int nextSigPos = firstSigPos;
//===== encode absolute values =====
const int inferSigPos = min_sub_pos;
int remAbsLevel = -1;
int numNonZero = 0;
int rightPixel, belowPixel, modAbsCoeff;
int lastScanPosPass1 = -1;
int lastScanPosPass2 = -1;
for (; nextSigPos <= min_sub_pos && maxCtxBins >= 4; nextSigPos++)
{
blk_pos = scan[nextSigPos];
int pos_x = blk_pos % width;
int pos_y = blk_pos / width;
coeff_t curr_coeff = coeff[blk_pos];
unsigned sigFlag = (curr_coeff != 0);
if (numNonZero || nextSigPos != inferSigPos)
{
cabac->cur_ctx = &cabac->ctx.transform_skip_sig[
kvz_context_get_sig_ctx_idx_abs_ts(coeff, pos_x, pos_y, width)
];
CABAC_BIN(cabac, sigFlag, "sig_coeff_flag");
maxCtxBins--;
}
if (sigFlag)
{
//===== encode sign's =====
int sign = curr_coeff < 0;
cabac->cur_ctx = &cabac->ctx.transform_skip_res_sign[
kvz_sign_ctx_id_abs_ts(coeff, pos_x, pos_y, width, 0)
];
CABAC_BIN(cabac, sign, "coeff_sign_flag");
maxCtxBins--;
numNonZero++;
rightPixel = pos_x > 0 ? coeff[pos_x + pos_y * width - 1] : 0;
belowPixel = pos_y > 0 ? coeff[pos_x + (pos_y - 1) * width] : 0;
modAbsCoeff = kvz_derive_mod_coeff(rightPixel, belowPixel, abs(curr_coeff), 0);
remAbsLevel = modAbsCoeff - 1;
unsigned gt1 = !!remAbsLevel;
cabac->cur_ctx = &cabac->ctx.transform_skip_gt1[
kvz_lrg1_ctx_id_abs_ts(coeff, pos_x, pos_y, width, 0)
];
CABAC_BIN(cabac, gt1, "abs_level_gtx_flag");
maxCtxBins--;
if (gt1)
{
remAbsLevel -= 1;
cabac->cur_ctx = &cabac->ctx.transform_skip_par;
CABAC_BIN(cabac, remAbsLevel & 1, "par_level_flag");
maxCtxBins--;
}
}
lastScanPosPass1 = nextSigPos;
}
int cutoffVal = 2;
int numGtBins = 4;
for (int scanPos = firstSigPos; scanPos <= min_sub_pos && maxCtxBins >= 4; scanPos++)
{
blk_pos = scan[scanPos];
int pos_x = blk_pos % width;
int pos_y = blk_pos / width;
unsigned absLevel;
rightPixel = pos_x > 0 ? coeff[pos_x + pos_y * width - 1] : 0;
belowPixel = pos_y > 0 ? coeff[pos_x + (pos_y - 1) * width] : 0;
absLevel = kvz_derive_mod_coeff(rightPixel, belowPixel, abs(coeff[blk_pos]), 0);
cutoffVal = 2;
for (int i = 0; i < numGtBins; i++)
{
if (absLevel >= cutoffVal)
{
unsigned gt2 = (absLevel >= (cutoffVal + 2));
cabac->cur_ctx = &cabac->ctx.transform_skip_gt2[cutoffVal >> 1];
CABAC_BIN(cabac, gt2, "abs_level_gtx_flag");
maxCtxBins--;
}
cutoffVal += 2;
}
lastScanPosPass2 = scanPos;
}
//===== coeff bypass ====
for (int scanPos = firstSigPos; scanPos <= min_sub_pos; scanPos++)
{
blk_pos = scan[scanPos];
int pos_x = blk_pos % width;
int pos_y = blk_pos / width;
unsigned absLevel;
rightPixel = pos_x > 0 ? coeff[pos_x + pos_y * width - 1] : 0;
belowPixel = pos_y > 0 ? coeff[pos_x + (pos_y - 1) * width] : 0;
cutoffVal = (scanPos <= lastScanPosPass2 ? 10 : (scanPos <= lastScanPosPass1 ? 2 : 0));
absLevel = kvz_derive_mod_coeff(rightPixel, belowPixel, abs(coeff[blk_pos]), 0 || !cutoffVal);
if (absLevel >= cutoffVal)
{
int rice = 1;
unsigned rem = scanPos <= lastScanPosPass1 ? (absLevel - cutoffVal) >> 1 : absLevel;
kvz_cabac_write_coeff_remain(cabac, rem, rice, 5);
if (absLevel && scanPos > lastScanPosPass1)
{
int sign = coeff[blk_pos] < 0;
CABAC_BIN_EP(cabac, sign, "coeff_sign_flag");
}
}
}
}
}
/**
* \brief Encode (X,Y) position of the last significant coefficient
*
@ -162,16 +332,25 @@ void kvz_encode_last_significant_xy(cabac_data_t * const cabac,
static void encode_chroma_tu(encoder_state_t* const state, int x, int y, int depth, const uint8_t width_c, const cu_info_t* cur_pu, int8_t* scan_idx) {
int x_local = (x >> 1) % LCU_WIDTH_C;
int y_local = (y >> 1) % LCU_WIDTH_C;
cabac_data_t* const cabac = &state->cabac;
*scan_idx = kvz_get_scan_order(cur_pu->type, cur_pu->intra.mode_chroma, depth);
const coeff_t *coeff_u = &state->coeff->u[xy_to_zorder(LCU_WIDTH_C, x_local, y_local)];
const coeff_t *coeff_v = &state->coeff->v[xy_to_zorder(LCU_WIDTH_C, x_local, y_local)];
if (cbf_is_set(cur_pu->cbf, depth, COLOR_U)) {
if(state->encoder_control->cfg.trskip_enable && width_c == 4){
cabac->cur_ctx = &cabac->ctx.transform_skip_model_chroma;
CABAC_BIN(cabac, cur_pu->tr_idx == MTS_SKIP, "transform_skip_flag");
}
kvz_encode_coeff_nxn(state, &state->cabac, coeff_u, width_c, 1, *scan_idx, NULL, false);
}
if (cbf_is_set(cur_pu->cbf, depth, COLOR_V)) {
if (state->encoder_control->cfg.trskip_enable && width_c == 4) {
cabac->cur_ctx = &cabac->ctx.transform_skip_model_chroma;
CABAC_BIN(cabac, cur_pu->tr_idx == MTS_SKIP, "transform_skip_flag");
}
kvz_encode_coeff_nxn(state, &state->cabac, coeff_v, width_c, 2, *scan_idx, NULL, false);
}
}
@ -182,6 +361,7 @@ static void encode_transform_unit(encoder_state_t * const state,
assert(depth >= 1 && depth <= MAX_PU_DEPTH);
const videoframe_t * const frame = state->tile->frame;
cabac_data_t* const cabac = &state->cabac;
const uint8_t width = LCU_WIDTH >> depth;
const uint8_t width_c = (depth == MAX_PU_DEPTH ? width : width / 2);
@ -209,8 +389,14 @@ static void encode_transform_unit(encoder_state_t * const state,
// CoeffNxN
// Residual Coding
if(state->encoder_control->cfg.trskip_enable && width == 4) {
cabac->cur_ctx = &cabac->ctx.transform_skip_model_luma;
CABAC_BIN(cabac, 1, "transform_skip_flag");
encode_ts_residual(state, cabac, coeff_y, width, 0, scan_idx);
}
else {
kvz_encode_coeff_nxn(state,
&state->cabac,
cabac,
coeff_y,
width,
0,
@ -218,6 +404,7 @@ static void encode_transform_unit(encoder_state_t * const state,
cur_pu,
true);
}
}
if (depth == MAX_DEPTH) {
// For size 4x4 luma transform the corresponding chroma transforms are

View file

@ -594,7 +594,11 @@ static void encoder_state_write_bitstream_seq_parameter_set(bitstream_t* stream,
WRITE_U(stream, (TR_MAX_LOG2_SIZE - 5) ? 1 : 0, 1, "sps_max_luma_transform_size_64_flag");
WRITE_U(stream, 0, 1, "sps_transform_skip_enabled_flag");
WRITE_U(stream, encoder->cfg.trskip_enable, 1, "sps_transform_skip_enabled_flag");
if (encoder->cfg.trskip_enable) {
WRITE_UE(stream, 0, "sps_log2_transform_skip_max_size_minus2"); // Only enable transformskip for 4x4 blocks for now
WRITE_U(stream, 0, 1, "sps_bdpcm_enabled_flag");
}
const uint8_t mts_selection = encoder->cfg.mts;
WRITE_U(stream, mts_selection ? 1 : 0, 1, "sps_mts_enabled_flag");
@ -694,6 +698,11 @@ static void encoder_state_write_bitstream_seq_parameter_set(bitstream_t* stream,
}
WRITE_U(stream, 0, 1, "sps_palette_enabled_flag");
if (encoder->cfg.trskip_enable /* || pcSPS->getPLTMode()*/) {
WRITE_UE(stream, KVZ_BIT_DEPTH, "log2_parallel_merge_level_minus2");
}
WRITE_U(stream, 0, 1, "sps_ibc_enabled_flag");
#if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
@ -1310,7 +1319,10 @@ void kvz_encoder_state_write_bitstream_slice_header(
if (state->encoder_control->cfg.signhide_enable) {
WRITE_U(stream, 1, 1, "sh_sign_data_hiding_used_flag");
}
if (state->encoder_control->cfg.trskip_enable && !state->encoder_control->cfg.signhide_enable /* && !cfg.dep_quant*/)
{
WRITE_U(stream, 0, 1, "sh_ts_residual_coding_disabled_flag");
}
if (state->frame->slicetype != KVZ_SLICE_I) {
// BT Size set only with non-I-frames, in I-frames the size is 32x32

View file

@ -85,16 +85,16 @@ static double get_cost(encoder_state_t * const state,
// Add the offset bit costs of signaling 'luma and chroma use trskip',
// versus signaling 'luma and chroma don't use trskip' to the SAD cost.
//const cabac_ctx_t *ctx = &state->cabac.ctx.transform_skip_model_luma;
double trskip_bits = 0.0;// CTX_ENTROPY_FBITS(ctx, 1) - CTX_ENTROPY_FBITS(ctx, 0);
const cabac_ctx_t *ctx = &state->cabac.ctx.transform_skip_model_luma;
double trskip_bits = CTX_ENTROPY_FBITS(ctx, 1) - CTX_ENTROPY_FBITS(ctx, 0);
/*
// ToDo: Check cost
if (state->encoder_control->chroma_format != KVZ_CSP_400) {
ctx = &state->cabac.ctx.transform_skip_model_chroma;
trskip_bits += 2.0 * (CTX_ENTROPY_FBITS(ctx, 1) - CTX_ENTROPY_FBITS(ctx, 0));
}
*/
double sad_cost = TRSKIP_RATIO * sad_func(pred, orig_block) + state->lambda_sqrt * trskip_bits;
if (sad_cost < satd_cost) {
@ -124,6 +124,7 @@ static void get_cost_dual(encoder_state_t * const state,
costs_out[0] = (double)satd_costs[0];
costs_out[1] = (double)satd_costs[1];
// TODO: width and height
if (TRSKIP_RATIO != 0 && width == 4 && state->encoder_control->cfg.trskip_enable) {
// If the mode looks better with SAD than SATD it might be a good
// candidate for transform skip. How much better SAD has to be is
@ -131,16 +132,16 @@ static void get_cost_dual(encoder_state_t * const state,
// Add the offset bit costs of signaling 'luma and chroma use trskip',
// versus signaling 'luma and chroma don't use trskip' to the SAD cost.
//const cabac_ctx_t *ctx = &state->cabac.ctx.transform_skip_model_luma;
double trskip_bits = 0.0;// CTX_ENTROPY_FBITS(ctx, 1) - CTX_ENTROPY_FBITS(ctx, 0);
const cabac_ctx_t *ctx = &state->cabac.ctx.transform_skip_model_luma;
double trskip_bits = CTX_ENTROPY_FBITS(ctx, 1) - CTX_ENTROPY_FBITS(ctx, 0);
/*
// ToDo: check cost
if (state->encoder_control->chroma_format != KVZ_CSP_400) {
ctx = &state->cabac.ctx.transform_skip_model_chroma;
trskip_bits += 2.0 * (CTX_ENTROPY_FBITS(ctx, 1) - CTX_ENTROPY_FBITS(ctx, 0));
}
*/
unsigned unsigned_sad_costs[PARALLEL_BLKS] = { 0 };
double sad_costs[PARALLEL_BLKS] = { 0 };