From 38eafbbf78dded91327ee790d4f2edea0614a428 Mon Sep 17 00:00:00 2001 From: Marko Viitanen Date: Fri, 30 Apr 2021 10:04:41 +0300 Subject: [PATCH] [LMCS] initial bitstream writing and LMCS structures --- src/Makefile.am | 2 + src/alf.c | 52 +++++++++++++---- src/encoder_state-bitstream.c | 24 +++++++- src/global.h | 6 ++ src/reshape.c | 97 +++++++++++++++++++++++++++++++ src/reshape.h | 105 ++++++++++++++++++++++++++++++++++ 6 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 src/reshape.c create mode 100644 src/reshape.h diff --git a/src/Makefile.am b/src/Makefile.am index 8525f622..69453f17 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -100,6 +100,8 @@ libkvazaar_la_SOURCES = \ rate_control.h \ rdo.c \ rdo.h \ + reshape.c \ + reshape.h \ sao.c \ sao.h \ scalinglist.c \ diff --git a/src/alf.c b/src/alf.c index 103ba411..867aaaad 100644 --- a/src/alf.c +++ b/src/alf.c @@ -11,6 +11,7 @@ #include "rdo.h" #include "strategies/strategies-sao.h" #include "kvz_math.h" +#include "reshape.h" #if MAX_NUM_CC_ALF_FILTERS>1 typedef struct filter_idx_count @@ -1574,6 +1575,42 @@ static void encode_alf_aps_flags(encoder_state_t * const state, } } + +// ToDo: Fill in LMCS APS +static void encode_lmcs_aps(encoder_state_t* const state, lmcs_aps* aps) +{ + bitstream_t* const stream = &state->stream; + //SliceReshapeInfo param = pcAPS->getReshaperAPSInfo(); + WRITE_UE(stream, 0/*param.reshaperModelMinBinIdx*/, "lmcs_min_bin_idx"); + WRITE_UE(stream, 16 - 1/*16 - 1 - param.reshaperModelMaxBinIdx*/, "lmcs_delta_max_bin_idx"); + + WRITE_UE(stream, 7/*param.maxNbitsNeededDeltaCW - 1*/, "lmcs_delta_cw_prec_minus1"); + /* + for (int i = param.reshaperModelMinBinIdx; i <= param.reshaperModelMaxBinIdx; i++) + { + int deltaCW = param.reshaperModelBinCWDelta[i]; + int signCW = (deltaCW < 0) ? 1 : 0; + int absCW = (deltaCW < 0) ? (-deltaCW) : deltaCW; + WRITE_CODE(absCW, param.maxNbitsNeededDeltaCW, "lmcs_delta_abs_cw[ i ]"); + if (absCW > 0) + { + WRITE_FLAG(signCW, "lmcs_delta_sign_cw_flag[ i ]"); + } + } + int deltaCRS = pcAPS->chromaPresentFlag ? param.chrResScalingOffset : 0; + int signCRS = (deltaCRS < 0) ? 1 : 0; + int absCRS = (deltaCRS < 0) ? (-deltaCRS) : deltaCRS; + if (pcAPS->chromaPresentFlag) + { + WRITE_CODE(absCRS, 3, "lmcs_delta_abs_crs"); + } + if (absCRS > 0) + { + WRITE_FLAG(signCRS, "lmcs_delta_sign_crs_flag"); + } + */ +} + static void encoder_state_write_adaptation_parameter_set(encoder_state_t * const state, alf_aps *aps) { #ifdef KVZ_DEBUG @@ -1590,10 +1627,10 @@ static void encoder_state_write_adaptation_parameter_set(encoder_state_t * const { encode_alf_aps_flags(state, aps); } - /*else if (aps->aps_type == T_LMCS_APS) + else if (aps->aps_type == T_LMCS_APS) { - codeLmcsAps(pcAPS); - }*/ + //encode_lmcs_aps(state); + } /*else if (aps->aps_type == T_SCALING_LIST_APS) { codeScalingListAps(pcAPS); @@ -1606,7 +1643,7 @@ static void encoder_state_write_adaptation_parameter_set(encoder_state_t * const //For example, in RA, update is on intra slice, but intra slice may not use reshaper static void encode_alf_aps_lmcs(encoder_state_t * const state) { - if (0 /*pcSlice->getSPS()->getUseLmcs()*/) + if (state->encoder_control->cfg.lmcs_enable) // ToDo: do something with LMCS {/* //only 1 LMCS data for 1 picture int apsId = picHeader->getLmcsAPSId(); @@ -1670,18 +1707,11 @@ static void encode_alf_aps(encoder_state_t * const state) if (write_aps) { - //actualTotalBits += xWriteAPS(accessUnit, aps); kvz_nal_write(stream, NAL_UNIT_PREFIX_APS, 0, state->frame->first_nal); state->frame->first_nal = false; encoder_state_write_adaptation_parameter_set(state, &aps); - //apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS); aps_map[aps_id + T_ALF_APS].b_changed = false; - - //CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP"); - /*assert(!(aps.aps_id != state->slice->apss[aps_id].aps_id - && aps_id != state->slice->tile_group_cc_alf_cr_aps_id - && aps_id != state->slice->tile_group_cc_alf_cr_aps_id)); //"Wrong APS id");*/ } } } diff --git a/src/encoder_state-bitstream.c b/src/encoder_state-bitstream.c index 46764160..e4f1924f 100644 --- a/src/encoder_state-bitstream.c +++ b/src/encoder_state-bitstream.c @@ -631,7 +631,7 @@ static void encoder_state_write_bitstream_seq_parameter_set(bitstream_t* stream, WRITE_U(stream, encoder->cfg.alf_type == KVZ_ALF_FULL, 1, "sps_ccalf_enabled_flag"); } - WRITE_U(stream, 0, 1, "sps_lmcs_enable_flag"); + WRITE_U(stream, encoder->cfg.lmcs_enable, 1, "sps_lmcs_enable_flag"); WRITE_U(stream, 0, 1, "sps_weighted_pred_flag"); // Use of Weighting Prediction (P_SLICE) WRITE_U(stream, 0, 1, "sps_weighted_bipred_flag"); // Use of Weighting Bi-Prediction (B_SLICE) @@ -1111,7 +1111,20 @@ static void kvz_encoder_state_write_bitstream_picture_header( state->tile->frame->alf_cc_enable_flag[COMPONENT_Cb] = false; state->tile->frame->alf_cc_enable_flag[COMPONENT_Cr] = false;*/ } + if (encoder->cfg.lmcs_enable) + { + WRITE_U(stream, 1, 1, "ph_lmcs_enabled_flag"); + + //if (picHeader->getLmcsEnabledFlag()) + { + WRITE_U(stream, 0, 2, "ph_lmcs_aps_id"); + if (encoder->chroma_format != KVZ_CSP_400) + { + WRITE_U(stream, 0, 1, "ph_chroma_residual_scale_flag"); // ToDo: LMCS Enable chroma scaling + } + } + } // getDeblockingFilterControlPresentFlag // END PICTURE HEADER @@ -1494,6 +1507,15 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state) // Adaptation parameter set (APS) kvz_encode_alf_adaptive_parameter_set(state); + if (state->encoder_control->cfg.lmcs_enable) { + // ToDo: Write LMCS APS NAL + /* + kvz_nal_write(stream, NAL_UNIT_PREFIX_APS, 0, state->frame->first_nal); + state->frame->first_nal = false; + encoder_state_write_adaptation_parameter_set(state, &aps); + */ + } + encoder_state_write_bitstream_children(state); if (state->encoder_control->cfg.hash != KVZ_HASH_NONE) { diff --git a/src/global.h b/src/global.h index 7e08f3f5..20d2ae3c 100644 --- a/src/global.h +++ b/src/global.h @@ -53,6 +53,12 @@ // VVC related definitions #define ENABLE_WPP_PARALLELISM 0 +//LMCS +#define PIC_CODE_CW_BINS 16 +#define PIC_ANALYZE_CW_BINS 32 +#define LMCS_SEG_NUM 32 +#define FP_PREC 11 +#define CSCALE_FP_PREC 11 /** * \defgroup Bitstream diff --git a/src/reshape.c b/src/reshape.c new file mode 100644 index 00000000..06475743 --- /dev/null +++ b/src/reshape.c @@ -0,0 +1,97 @@ +/***************************************************************************** + * This file is part of Kvazaar HEVC encoder. + * + * Copyright (C) 2013-2021 Tampere University of Technology and others (see + * COPYING file). + * + * Kvazaar is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with Kvazaar. If not, see . + ****************************************************************************/ + +#include "reshape.h" + +#include +#include +#include +#include + +#include "cabac.h" +#include "rdo.h" +#include "strategies/strategies-sao.h" +#include "kvz_math.h" + +void kvz_free_lmcs_aps(lmcs_aps* aps) +{ + FREE_POINTER(aps->m_invLUT); + FREE_POINTER(aps->m_fwdLUT); + +} + +void kvz_init_lmcs_seq_stats(lmcs_seq_info* stats, int32_t m_binNum) +{ + for (int i = 0; i < m_binNum; i++) + { + stats->binVar[i] = 0.0; + stats->binHist[i] = 0.0; + stats->normVar[i] = 0.0; + } + stats->nonZeroCnt = 0; + stats->weightVar = 0.0; + stats->weightNorm = 0.0; + stats->minBinVar = 0.0; + stats->maxBinVar = 0.0; + stats->meanBinVar = 0.0; + stats->ratioStdU = 0.0; + stats->ratioStdV = 0.0; +} + +void kvz_init_lmcs_aps(lmcs_aps* aps, int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight, int bitDepth) +{ + aps->m_lumaBD = bitDepth; + aps->m_reshapeLUTSize = 1 << aps->m_lumaBD; + aps->m_initCWAnalyze = aps->m_reshapeLUTSize / PIC_ANALYZE_CW_BINS; + aps->m_initCW = aps->m_reshapeLUTSize / PIC_CODE_CW_BINS; + + aps->m_fwdLUT = calloc(1, sizeof(kvz_pixel) * aps->m_reshapeLUTSize); + + aps->m_invLUT = calloc(1, sizeof(kvz_pixel) * aps->m_reshapeLUTSize); + + memset(aps->m_binCW, 0, sizeof(uint16_t) * PIC_ANALYZE_CW_BINS); + memset(aps->m_binImportance, 0, sizeof(uint32_t) * PIC_ANALYZE_CW_BINS); + memset(aps->m_reshapePivot, 0, sizeof(kvz_pixel) * PIC_CODE_CW_BINS + 1); + memset(aps->m_inputPivot, 0, sizeof(kvz_pixel) * PIC_CODE_CW_BINS + 1); + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) { + aps->m_fwdScaleCoef[i] = 1 << FP_PREC; + } + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) { + aps->m_invScaleCoef[i] = 1 << FP_PREC; + } + + for (int i = 0; i < PIC_CODE_CW_BINS; i++) { + aps->m_chromaAdjHelpLUT[i] = 1 << CSCALE_FP_PREC; + } + + aps->m_sliceReshapeInfo.sliceReshaperEnableFlag = true; + aps->m_sliceReshapeInfo.enableChromaAdj = true; + aps->m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true; + aps->m_sliceReshapeInfo.reshaperModelMinBinIdx = 0; + aps->m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1; + memset(aps->m_sliceReshapeInfo.reshaperModelBinCWDelta, 0, (PIC_CODE_CW_BINS) * sizeof(int)); + aps->m_sliceReshapeInfo.chrResScalingOffset = 0; + + aps->m_binNum = PIC_CODE_CW_BINS; + kvz_init_lmcs_seq_stats(&aps->m_srcSeqStats, aps->m_binNum); + kvz_init_lmcs_seq_stats(&aps->m_rspSeqStats, aps->m_binNum); +} \ No newline at end of file diff --git a/src/reshape.h b/src/reshape.h new file mode 100644 index 00000000..9038eb1b --- /dev/null +++ b/src/reshape.h @@ -0,0 +1,105 @@ +#pragma once +/***************************************************************************** + * This file is part of Kvazaar HEVC encoder. + * + * Copyright (C) 2013-2021 Tampere University of Technology and others (see + * COPYING file). + * + * Kvazaar is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with Kvazaar. If not, see . + ****************************************************************************/ + +/** +* \ingroup Reconstruction +* \file +* LMCS reshape. +*/ + +#include "checkpoint.h" +#include "cu.h" +#include "encoder.h" +#include "encoderstate.h" +#include "global.h" // IWYU pragma: keep +#include "kvazaar.h" +#include "videoframe.h" +#include "image.h" +#include "nal.h" + +typedef struct lmcs_seq_info +{ + double binVar[32]; + double binHist[32]; + double normVar[32]; + int nonZeroCnt; + double weightVar; + double weightNorm; + double minBinVar; + double maxBinVar; + double meanBinVar; + double ratioStdU; + double ratioStdV; +} lmcs_seq_info; + +typedef struct SliceReshapeInfo { + bool sliceReshaperEnableFlag; + bool sliceReshaperModelPresentFlag; + unsigned enableChromaAdj; + uint32_t reshaperModelMinBinIdx; + uint32_t reshaperModelMaxBinIdx; + int reshaperModelBinCWDelta[PIC_CODE_CW_BINS]; + int maxNbitsNeededDeltaCW; + int chrResScalingOffset; +} SliceReshapeInfo; + +typedef struct lmcs_aps { + SliceReshapeInfo m_sliceReshapeInfo; + bool m_CTUFlag; + bool m_recReshaped; + kvz_pixel* m_invLUT; + kvz_pixel* m_fwdLUT; + int32_t m_chromaAdjHelpLUT[PIC_CODE_CW_BINS]; + uint16_t m_binCW[PIC_ANALYZE_CW_BINS]; + uint16_t m_initCW; + bool m_reshape; + kvz_pixel m_reshapePivot[PIC_CODE_CW_BINS + 1]; + kvz_pixel m_inputPivot[PIC_CODE_CW_BINS + 1]; + int32_t m_fwdScaleCoef[PIC_CODE_CW_BINS]; + int32_t m_invScaleCoef[PIC_CODE_CW_BINS]; + int m_lumaBD; + int m_reshapeLUTSize; + int m_chromaScale; + int m_vpduX; + int m_vpduY; + + bool m_exceedSTD; + uint32_t m_binImportance[PIC_ANALYZE_CW_BINS]; + int m_tcase; + int m_rateAdpMode; + bool m_useAdpCW; + uint16_t m_initCWAnalyze; + //ReshapeCW m_reshapeCW; + kvz_pixel m_cwLumaWeight[PIC_CODE_CW_BINS]; + double m_chromaWeight; + int m_chromaAdj; + int m_binNum; + lmcs_seq_info m_srcSeqStats; + lmcs_seq_info m_rspSeqStats; + +} lmcs_aps; + + +void kvz_free_lmcs_aps(lmcs_aps* aps); + +void kvz_init_lmcs_seq_stats(lmcs_seq_info* stats, int32_t m_binNum); + +void kvz_init_lmcs_aps(lmcs_aps* aps, int picWidth, int picHeight, uint32_t maxCUWidth, uint32_t maxCUHeight, int bitDepth); \ No newline at end of file