From 5b46fbd878ab668fb995efce8b3bc22aac8ef197 Mon Sep 17 00:00:00 2001 From: Sami Ahovainio Date: Tue, 21 May 2019 12:28:05 +0300 Subject: [PATCH] Added multi_ref_idx variable for intra coding (is 0 throughout the code for now). Modified prediction flag writing. Chroma pred flag remains unchanged (ToDo). Added bitstream debug printing on VERBOSE mode. --- src/bitstream.c | 17 ++++- src/cabac.h | 3 +- src/context.c | 15 +++- src/cu.h | 1 + src/encode_coding_tree.c | 150 ++++++++++++++++++++++++++------------- src/global.h | 5 ++ src/nal.c | 12 ++++ src/search.c | 1 + 8 files changed, 148 insertions(+), 56 deletions(-) diff --git a/src/bitstream.c b/src/bitstream.c index 7d83bfbe..78a203f2 100644 --- a/src/bitstream.c +++ b/src/bitstream.c @@ -266,8 +266,16 @@ void kvz_bitstream_put_se(bitstream_t *stream, int32_t data) void kvz_bitstream_add_rbsp_trailing_bits(bitstream_t * const stream) { kvz_bitstream_put(stream, 1, 1); +#if VERBOSE + printf("%-40s u(%d) : %d\n", "rbsp_stop_one_bit", 1, 1); +#endif if ((stream->cur_bit & 7) != 0) { - kvz_bitstream_put(stream, 0, 8 - (stream->cur_bit & 7)); +#if VERBOSE + for (int i = 0; i < (8 - stream->cur_bit) & 7; i++) { + printf("%-40s u(%d) : %d\n", "rbsp_alignment_zero_bit", 1, 0); + } +#endif + kvz_bitstream_put(stream, 0, (8 - stream->cur_bit) & 7); } } @@ -287,6 +295,11 @@ void kvz_bitstream_align(bitstream_t * const stream) void kvz_bitstream_align_zero(bitstream_t * const stream) { if ((stream->cur_bit & 7) != 0) { - kvz_bitstream_put(stream, 0, 8 - (stream->cur_bit & 7)); +#if VERBOSE + for (int i = 0; i < (8 - stream->cur_bit) & 7; i++) { + printf("%-40s u(%d) : %d\n", "rbsp_alignment_zero_bit", 1, 0); + } +#endif + kvz_bitstream_put(stream, 0, (8 - stream->cur_bit) & 7); } } diff --git a/src/cabac.h b/src/cabac.h index 85f9d83d..45e19f4f 100644 --- a/src/cabac.h +++ b/src/cabac.h @@ -60,7 +60,7 @@ typedef struct cabac_ctx_t intra_subpart_model[2]; //!< \brief intra sub part context models cabac_ctx_t chroma_pred_model[3]; cabac_ctx_t inter_dir[5]; - cabac_ctx_t qt_cbf_model_luma[4]; + cabac_ctx_t qt_cbf_model_luma[5]; cabac_ctx_t qt_cbf_model_cr[2]; cabac_ctx_t qt_cbf_model_cb[5]; cabac_ctx_t cu_qp_delta_abs[3]; @@ -85,6 +85,7 @@ typedef struct cabac_ctx_t mvp_idx_model[2]; cabac_ctx_t cu_qt_root_cbf_model; cabac_ctx_t sig_coeff_group_model[8]; + cabac_ctx_t luma_planar_model[2]; } ctx; } cabac_data_t; diff --git a/src/context.c b/src/context.c index 194d6cd4..7b282699 100644 --- a/src/context.c +++ b/src/context.c @@ -78,6 +78,13 @@ static const uint8_t INIT_INTRA_PRED_MODE[4] = { 154, 154, 170, 6 }; +static const uint8_t INIT_INTRA_LUMA_PLANAR_MODE[4][2] = { + { 125, 125, }, + { 139, 139, }, + { 110, 154, }, + { 4, 5, }, + }; + static const uint8_t INIT_CHROMA_PRED_MODE[4][3] = { { 137, 139, 140, }, { 138, 139, 169, }, @@ -345,10 +352,11 @@ void kvz_init_contexts(encoder_state_t *state, int8_t QP, int8_t slice) kvz_ctx_init(&cabac->ctx.cu_qt_root_cbf_model, QP, INIT_QT_ROOT_CBF[slice][0], INIT_QT_ROOT_CBF[3][0]); for (i = 0; i < 2; i++) { - kvz_ctx_init(&cabac->ctx.qt_cbf_model_cr[i], QP, INIT_QT_CBF[slice][i + 9], INIT_QT_CBF[3][i + 9]); + kvz_ctx_init(&cabac->ctx.qt_cbf_model_cr[i], QP, INIT_QT_CBF[slice][i + 10], INIT_QT_CBF[3][i + 10]); kvz_ctx_init(&cabac->ctx.cu_mvd_model[i], QP, INIT_MVD[slice][i], INIT_MVD[3][i]); kvz_ctx_init(&cabac->ctx.cu_ref_pic_model[i], QP, INIT_REF_PIC[slice][i], INIT_REF_PIC[3][i]); kvz_ctx_init(&cabac->ctx.mvp_idx_model[i], QP, INIT_MVP_IDX[slice][i], INIT_MVP_IDX[3][i]); + kvz_ctx_init(&cabac->ctx.luma_planar_model[i], QP, INIT_INTRA_LUMA_PLANAR_MODE[slice][i], INIT_INTRA_LUMA_PLANAR_MODE[3][i]); } @@ -357,7 +365,7 @@ void kvz_init_contexts(encoder_state_t *state, int8_t QP, int8_t slice) } for (i = 0; i < 4; i++) { - kvz_ctx_init(&cabac->ctx.qt_cbf_model_luma[i], QP, INIT_QT_CBF[slice][i], INIT_QT_CBF[3][i]); + kvz_ctx_init(&cabac->ctx.part_size_model[i], QP, INIT_PART_SIZE[slice][i], INIT_PART_SIZE[3][i]); kvz_ctx_init(&cabac->ctx.cu_ctx_last_y_chroma[i], QP, INIT_LAST_X[slice][i + 25], INIT_LAST_X[3][i + 25]); @@ -365,7 +373,8 @@ void kvz_init_contexts(encoder_state_t *state, int8_t QP, int8_t slice) } for (i = 0; i < 5; i++) { - kvz_ctx_init(&cabac->ctx.qt_cbf_model_cb[i], QP, INIT_QT_CBF[slice][i + 4], INIT_QT_CBF[3][i + 4]); + kvz_ctx_init(&cabac->ctx.qt_cbf_model_luma[i], QP, INIT_QT_CBF[slice][i], INIT_QT_CBF[3][i]); + kvz_ctx_init(&cabac->ctx.qt_cbf_model_cb[i], QP, INIT_QT_CBF[slice][i + 5], INIT_QT_CBF[3][i + 5]); kvz_ctx_init(&cabac->ctx.inter_dir[i], QP, INIT_INTER_DIR[slice][i], INIT_INTER_DIR[3][i]); } diff --git a/src/cu.h b/src/cu.h index 78301ab6..6c40f7fe 100644 --- a/src/cu.h +++ b/src/cu.h @@ -143,6 +143,7 @@ typedef struct #if KVZ_SEL_ENCRYPTION int8_t mode_encry; #endif + uint8_t multi_ref_idx; } intra; struct { int16_t mv[2][2]; // \brief Motion vectors for L0 and L1 diff --git a/src/encode_coding_tree.c b/src/encode_coding_tree.c index 31cad281..71720f88 100644 --- a/src/encode_coding_tree.c +++ b/src/encode_coding_tree.c @@ -975,11 +975,28 @@ static void encode_intra_coding_unit(encoder_state_t * const state, #endif // Intra Subpartition mode - bool enough_samples = kvz_g_convert_to_bit[(LCU_WIDTH >> depth)] * 2 > kvz_g_convert_to_bit[4 /* MIN_TB_SIZEY*/]; + uint32_t width = (LCU_WIDTH >> depth); + uint32_t height = (LCU_WIDTH >> depth); + + bool enough_samples = kvz_g_convert_to_bit[width] + kvz_g_convert_to_bit[height] > (kvz_g_convert_to_bit[4 /* MIN_TB_SIZEY*/] << 1); + uint8_t isp_mode = 0; + // ToDo: add height comparison + isp_mode += ((width > TR_MAX_WIDTH) || !enough_samples) ? 1 : 0; + isp_mode += ((height > TR_MAX_WIDTH) || !enough_samples) ? 2 : 0; bool allow_isp = enough_samples; - if (allow_isp) { - cabac->cur_ctx = &(cabac->ctx.intra_subpart_model[0]); - CABAC_BIN(cabac, 0, "intra_subPartitions"); + if (isp_mode != 0) { + if (isp_mode) { + cabac->cur_ctx = &(cabac->ctx.intra_subpart_model[0]); + CABAC_BIN(cabac, 0, "intra_subPartitions"); + } else { + cabac->cur_ctx = &(cabac->ctx.intra_subpart_model[0]); + CABAC_BIN(cabac, 1, "intra_subPartitions"); + // ToDo: complete this if-clause + if (isp_mode == 3) { + cabac->cur_ctx = &(cabac->ctx.intra_subpart_model[1]); + CABAC_BIN(cabac, allow_isp - 1, "intra_subPart_ver_hor"); + } + } } // PREDINFO CODING @@ -990,6 +1007,7 @@ static void encode_intra_coding_unit(encoder_state_t * const state, const int num_pred_units = kvz_part_mode_num_parts[cur_cu->part_size]; const int cu_width = LCU_WIDTH >> depth; + cabac->cur_ctx = &(cabac->ctx.intra_mode_model); for (int j = 0; j < num_pred_units; ++j) { const int pu_x = PU_GET_X(cur_cu->part_size, cu_width, x, j); const int pu_y = PU_GET_Y(cur_cu->part_size, cu_width, y, j); @@ -1024,18 +1042,26 @@ static void encode_intra_coding_unit(encoder_state_t * const state, } } flag[j] = (mpm_preds[j] == -1) ? 0 : 1; - + if (!(cur_pu->intra.multi_ref_idx || (isp_mode))) { + CABAC_BIN(cabac, flag[j], "prev_intra_luma_pred_flag"); + } } - cabac->cur_ctx = &(cabac->ctx.intra_mode_model); - for (int j = 0; j < num_pred_units; ++j) { - CABAC_BIN(cabac, flag[j], "prev_intra_luma_pred_flag"); - } + + for (int j = 0; j < num_pred_units; ++j) { // Signal index of the prediction mode in the prediction list. if (flag[j]) { - CABAC_BIN_EP(cabac, (mpm_preds[j] > 0 ? 1 : 0), "mpm_idx"); + + const int pu_x = PU_GET_X(cur_cu->part_size, cu_width, x, j); + const int pu_y = PU_GET_Y(cur_cu->part_size, cu_width, y, j); + const cu_info_t *cur_pu = kvz_cu_array_at_const(frame->cu_array, pu_x, pu_y); + cabac->cur_ctx = &(cabac->ctx.luma_planar_model[(isp_mode ? 0 : 1)]); + if (cur_pu->intra.multi_ref_idx == 0) { + CABAC_BIN(cabac, (mpm_preds[j] > 0 ? 1 : 0), "mpm_idx_luma_planar"); + } + //CABAC_BIN_EP(cabac, (mpm_preds[j] > 0 ? 1 : 0), "mpm_idx"); if (mpm_preds[j] > 0) { CABAC_BIN_EP(cabac, (mpm_preds[j] > 1 ? 1 : 0), "mpm_idx"); } else if (mpm_preds[j] > 1) { @@ -1093,45 +1119,68 @@ static void encode_intra_coding_unit(encoder_state_t * const state, // Code chroma prediction mode. if (state->encoder_control->chroma_format != KVZ_CSP_400) { - unsigned pred_mode = 67; - unsigned chroma_pred_modes[4] = {0, 50, 18, 1}; + unsigned pred_mode = 0; + unsigned chroma_pred_modes[8] = {0, 50, 18, 1, 67, 68, 69, 70}; + const int pu_x = PU_GET_X(cur_cu->part_size, cu_width, x, 0); + const int pu_y = PU_GET_Y(cur_cu->part_size, cu_width, y, 0); + const cu_info_t *first_pu = kvz_cu_array_at_const(frame->cu_array, pu_x, pu_y); + int8_t chroma_intra_dir = first_pu->intra.mode_chroma; + int8_t luma_intra_dir = first_pu->intra.mode; - if (intra_pred_mode_chroma == intra_pred_mode_actual[0]) { - pred_mode = 68; - } else if (intra_pred_mode_chroma == 66) { - // Angular 66 mode is possible only if intra pred mode is one of the - // possible chroma pred modes, in which case it is signaled with that - // duplicate mode. - for (int i = 0; i < 4; ++i) { - if (intra_pred_mode_actual[0] == chroma_pred_modes[i]) pred_mode = i; - } - } else { - for (int i = 0; i < 4; ++i) { - if (intra_pred_mode_chroma == chroma_pred_modes[i]) pred_mode = i; - } - } - - // pred_mode == 67 mean intra_pred_mode_chroma is something that can't - // be coded. - assert(pred_mode != 67); - - /** - * Table 9-35 - Binarization for intra_chroma_pred_mode - * intra_chroma_pred_mode bin_string - * 4 0 - * 0 100 - * 1 101 - * 2 110 - * 3 111 - * Table 9-37 - Assignment of ctxInc to syntax elements with context coded bins - * intra_chroma_pred_mode[][] = 0, bypass, bypass - */ + bool derived_mode = chroma_intra_dir == 70; cabac->cur_ctx = &(cabac->ctx.chroma_pred_model[0]); - if (pred_mode == 68) { - CABAC_BIN(cabac, 0, "intra_chroma_pred_mode"); - } else { - CABAC_BIN(cabac, 1, "intra_chroma_pred_mode"); - CABAC_BINS_EP(cabac, pred_mode, 2, "intra_chroma_pred_mode"); + CABAC_BIN(cabac, derived_mode ? 0 : 1, "intra_chroma_pred_mode"); + + + if (!derived_mode) { + /*for (int i = 0; i < 4; i++) { + if (luma_intra_dir == chroma_pred_modes[i]) { + chroma_pred_modes[i] = 66; + break; + } + }*/ + for (; pred_mode < 8; pred_mode++) { + if (chroma_intra_dir == chroma_pred_modes[pred_mode]) { + break; + } + } + /*else if (intra_pred_mode_chroma == 66) { + // Angular 66 mode is possible only if intra pred mode is one of the + // possible chroma pred modes, in which case it is signaled with that + // duplicate mode. + for (int i = 0; i < 4; ++i) { + if (intra_pred_mode_actual[0] == chroma_pred_modes[i]) pred_mode = i; + } + } + else { + for (int i = 0; i < 4; ++i) { + if (intra_pred_mode_chroma == chroma_pred_modes[i]) pred_mode = i; + } + } + + // pred_mode == 67 mean intra_pred_mode_chroma is something that can't + // be coded. + assert(pred_mode != 67); + */ + /** + * Table 9-35 - Binarization for intra_chroma_pred_mode + * intra_chroma_pred_mode bin_string + * 4 0 + * 0 100 + * 1 101 + * 2 110 + * 3 111 + * Table 9-37 - Assignment of ctxInc to syntax elements with context coded bins + * intra_chroma_pred_mode[][] = 0, bypass, bypass + */ + /*cabac->cur_ctx = &(cabac->ctx.chroma_pred_model[0]); + if (pred_mode == 68) { + CABAC_BIN(cabac, 0, "intra_chroma_pred_mode"); + } + else { + CABAC_BIN(cabac, 1, "intra_chroma_pred_mode");*/ + CABAC_BINS_EP(cabac, pred_mode, 2, "intra_chroma_pred_mode"); + //} } } @@ -1311,10 +1360,10 @@ void kvz_encode_coding_tree(encoder_state_t * const state, bool allow_split = qt_split | bh_split | bv_split | th_split | tv_split; - if (no_split && allow_split) { - split_model = 0; + + // Get left and top block split_flags and if they are present and true, increase model number // ToDo: should use height and width to increase model, PU_GET_W() ? if (left_cu && GET_SPLITDATA(left_cu, depth) == 1) { @@ -1337,8 +1386,9 @@ void kvz_encode_coding_tree(encoder_state_t * const state, split_model += 3 * (split_num >> 1); cabac->cur_ctx = &(cabac->ctx.split_flag_model[split_model]); - CABAC_BIN(cabac, split_flag, "SplitFlag"); + CABAC_BIN(cabac, !(implicit_split_mode == KVZ_NO_SPLIT), "SplitFlag"); } + if (implicit_split_mode == KVZ_NO_SPLIT) return; if (!split_flag) return; diff --git a/src/global.h b/src/global.h index 4edba2e5..c570b32f 100644 --- a/src/global.h +++ b/src/global.h @@ -104,11 +104,16 @@ typedef int16_t coeff_t; //#define VERBOSE 1 +//#define KVZ_DEBUG_PRINT_CABAC 1 +//#define KVZ_DEBUG 1 /* CONFIG VARIABLES */ //spec: references to variables defined in Rec. ITU-T H.265 (04/2013) +// VVC flags +#define RDPCM 1 + //! Limits for prediction block sizes. 0 = 64x64, 4 = 4x4. #define PU_DEPTH_INTER_MIN 0 #define PU_DEPTH_INTER_MAX 3 diff --git a/src/nal.c b/src/nal.c index 3b98ca06..27b6675e 100644 --- a/src/nal.c +++ b/src/nal.c @@ -22,6 +22,7 @@ #include "bitstream.h" #include "strategies/strategies-nal.h" +#include /** @@ -36,6 +37,10 @@ void kvz_nal_write(bitstream_t * const bitstream, const uint8_t nal_type, const uint8_t start_code_prefix_one_3bytes = 0x01; const uint8_t zero = 0x00; +#ifdef KVZ_DEBUG + printf("=========== NAL unit ===========\n"); +#endif + // zero_byte (0x00) shall be present in the byte stream NALU of VPS, SPS // and PPS, or the first NALU of an access unit if(long_start_code) @@ -54,6 +59,13 @@ void kvz_nal_write(bitstream_t * const bitstream, const uint8_t nal_type, // 5bits of nuh_layer_id + nuh_temporal_id_plus1(3) byte = (temporal_id + 1) & 7; kvz_bitstream_writebyte(bitstream, byte); + +#if VERBOSE + printf("%-40s u(%d) : %d\n", "forbidden_zero_bit", 1, 0); + printf("%-40s u(%d) : %d\n", "nal_unit_type", 6, nal_type); + printf("%-40s u(%d) : %d\n", "nuh_layer_id", 6, temporal_id); + printf("%-40s u(%d) : %d\n", "nuh_temporal_id", 3, temporal_id + 1); +#endif } /*! diff --git a/src/search.c b/src/search.c index 51669c95..3a481acd 100644 --- a/src/search.c +++ b/src/search.c @@ -417,6 +417,7 @@ static double search_cu(encoder_state_t * const state, int x, int y, int depth, cur_cu->type = CU_NOTSET; cur_cu->part_size = SIZE_2Nx2N; cur_cu->qp = state->qp; + cur_cu->intra.multi_ref_idx = 0; // If the CU is completely inside the frame at this depth, search for // prediction modes at this depth.