Estimate coeff cost based on transform stats av1_est_coeff_entropy(): estimate coeff cost av1_est_txfm_block_entropy(): estimate transform block cost av1_laplace_prob(): compute the probability of qcoeff w.r.t. a Laplace distribution BUG=aomedia:3018 Change-Id: I3a6fd87030f7dda19e506e1371a3c365e73c7ed2
diff --git a/av1/common/mv.h b/av1/common/mv.h index be539e8..3203bf7 100644 --- a/av1/common/mv.h +++ b/av1/common/mv.h
@@ -12,6 +12,8 @@ #ifndef AOM_AV1_COMMON_MV_H_ #define AOM_AV1_COMMON_MV_H_ +#include <stdlib.h> + #include "av1/common/common.h" #include "av1/common/common_data.h" #include "aom_dsp/aom_filter.h"
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c index f1f9cc0..00dfd2f 100644 --- a/av1/encoder/tpl_model.c +++ b/av1/encoder/tpl_model.c
@@ -1722,11 +1722,9 @@ aom_clear_system_state(); } -#define EPSILON (0.0000001) - double av1_exponential_entropy(double q_step, double b) { aom_clear_system_state(); - double z = fmax(exp(-q_step / b), EPSILON); + double z = fmax(exp(-q_step / b), TPL_EPSILON); return -log2(1 - z) - z * log2(z) / (1 - z); } @@ -1734,7 +1732,7 @@ aom_clear_system_state(); // zero bin's size is zero_bin_ratio * q_step // non-zero bin's size is q_step - double z = fmax(exp(-zero_bin_ratio / 2 * q_step / b), EPSILON); + double z = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON); double h = av1_exponential_entropy(q_step, b); double r = -(1 - z) * log2(1 - z) - z * log2(z) + z * (h + 1); return r; @@ -1758,3 +1756,35 @@ est_rate *= block_count; return est_rate; } + +double av1_estimate_coeff_entropy(double q_step, double b, + double zero_bin_ratio, int qcoeff) { + int abs_qcoeff = abs(qcoeff); + double z0 = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON); + if (abs_qcoeff == 0) { + double r = -log2(1 - z0); + return r; + } else { + double z = fmax(exp(-q_step / b), TPL_EPSILON); + double r = 1 - log2(z0) - log2(1 - z) - (abs_qcoeff - 1) * log2(z); + return r; + } +} + +double av1_estimate_txfm_block_entropy(int q_index, + const double *abs_coeff_mean, + int *qcoeff_arr, int coeff_num) { + double zero_bin_ratio = 2; + double dc_q_step = av1_dc_quant_QTX(q_index, 0, AOM_BITS_8) / 4.; + double ac_q_step = av1_ac_quant_QTX(q_index, 0, AOM_BITS_8) / 4.; + double est_rate = 0; + // dc coeff + est_rate += av1_estimate_coeff_entropy(dc_q_step, abs_coeff_mean[0], + zero_bin_ratio, qcoeff_arr[0]); + // ac coeff + for (int i = 1; i < coeff_num; ++i) { + est_rate += av1_estimate_coeff_entropy(ac_q_step, abs_coeff_mean[i], + zero_bin_ratio, qcoeff_arr[i]); + } + return est_rate; +}
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h index 49f1605..44c712f 100644 --- a/av1/encoder/tpl_model.h +++ b/av1/encoder/tpl_model.h
@@ -22,7 +22,14 @@ struct EncodeFrameParams; struct EncodeFrameInput; -#include "av1/encoder/encoder.h" +#include "config/aom_config.h" + +#include "aom_scale/yv12config.h" + +#include "av1/common/mv.h" +#include "av1/common/scale.h" +#include "av1/encoder/block.h" +#include "av1/encoder/lookahead.h" static INLINE BLOCK_SIZE convert_length_to_bsize(int length) { switch (length) { @@ -82,6 +89,8 @@ #define MAX_TPL_EXTEND (MAX_LAG_BUFFERS - MAX_GF_INTERVAL) #define TPL_DEP_COST_SCALE_LOG2 4 +#define TPL_EPSILON 0.0000001 + typedef struct TplTxfmStats { double abs_coeff_sum[256]; // Assume we are using 16x16 transform block int txfm_block_count; @@ -277,7 +286,7 @@ /*!\brief Compute the frame rate using transform block stats * * Assume each position i in the transform block is of Laplace distribution - * with maximum absolute deviation abs_coeff_mean[i] + * with mean absolute deviation abs_coeff_mean[i] * * Then we can use av1_laplace_entropy() to compute the expected frame * rate. @@ -286,7 +295,7 @@ * * \param[in] q_index quantizer index * \param[in] block_count number of transform blocks - * \param[in] abs_coeff_mean array of maximum absolute deviation + * \param[in] abs_coeff_mean array of mean absolute deviation * \param[in] coeff_num number of coefficients per transform block * * \return expected frame rate @@ -305,6 +314,40 @@ */ void av1_tpl_stats_init_txfm_stats(TplDepFrame *tpl_frame, int coeff_num); +/*!\brief Estimate coefficient entropy using Laplace dsitribution + * + *\ingroup tpl_modelling + * + * This function is equivalent to -log2(laplace_prob()), where laplace_prob() is + * defined in tpl_model_test.cc + * + * \param[in] q_step quantizer step size without any scaling + * \param[in] b mean absolute deviation of Laplace distribution + * \param[in] zero_bin_ratio zero bin's size is zero_bin_ratio * q_step + * \param[in] qcoeff quantized coefficient + * + * \return estimated coefficient entropy + * + */ +double av1_estimate_coeff_entropy(double q_step, double b, + double zero_bin_ratio, int qcoeff); + +/*!\brief Estimate entropy of a transform block using Laplace dsitribution + * + *\ingroup tpl_modelling + * + * \param[in] q_index quantizer index + * \param[in] abs_coeff_mean array of mean absolute deviations + * \param[in] qcoeff_arr array of quantized coefficients + * \param[in] coeff_num number of coefficients per transform block + * + * \return estimated transform block entropy + * + */ +double av1_estimate_txfm_block_entropy(int q_index, + const double *abs_coeff_mean, + int *qcoeff_arr, int coeff_num); + /*!\endcond */ #ifdef __cplusplus } // extern "C"
diff --git a/test/test.cmake b/test/test.cmake index be485f3..5657859 100644 --- a/test/test.cmake +++ b/test/test.cmake
@@ -143,13 +143,15 @@ "${AOM_ROOT}/test/screen_content_test.cc" "${AOM_ROOT}/test/segment_binarization_sync.cc" "${AOM_ROOT}/test/still_picture_test.cc" + "${AOM_ROOT}/test/temporal_filter_test.cc" "${AOM_ROOT}/test/tile_config_test.cc" "${AOM_ROOT}/test/tile_independence_test.cc" - "${AOM_ROOT}/test/temporal_filter_test.cc") + "${AOM_ROOT}/test/tpl_model_test.cc") if(CONFIG_REALTIME_ONLY) list(REMOVE_ITEM AOM_UNIT_TEST_COMMON_SOURCES "${AOM_ROOT}/test/cnn_test.cc" - "${AOM_ROOT}/test/selfguided_filter_test.cc") + "${AOM_ROOT}/test/selfguided_filter_test.cc" + "${AOM_ROOT}/test/tpl_model_test.cc") endif() if(NOT CONFIG_AV1_HIGHBITDEPTH) list(REMOVE_ITEM AOM_UNIT_TEST_COMMON_SOURCES
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc new file mode 100644 index 0000000..72f5ebf --- /dev/null +++ b/test/tpl_model_test.cc
@@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include "av1/encoder/tpl_model.h" + +#include <cstdlib> + +#include "third_party/googletest/src/googletest/include/gtest/gtest.h" + +namespace { + +double laplace_prob(double q_step, double b, double zero_bin_ratio, + int qcoeff) { + int abs_qcoeff = abs(qcoeff); + double z0 = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON); + if (abs_qcoeff == 0) { + double p0 = 1 - z0; + return p0; + } else { + assert(abs_qcoeff > 0); + double z = fmax(exp(-q_step / b), TPL_EPSILON); + double p = z0 / 2 * (1 - z) * pow(z, abs_qcoeff - 1); + return p; + } +} + +TEST(TplModelTest, TransformCoeffEntropyTest1) { + // Check the consistency between av1_estimate_coeff_entropy() and + // laplace_prob() + double b = 1; + double q_step = 1; + double zero_bin_ratio = 2; + for (int qcoeff = -256; qcoeff < 256; ++qcoeff) { + double rate = av1_estimate_coeff_entropy(q_step, b, zero_bin_ratio, qcoeff); + double prob = laplace_prob(q_step, b, zero_bin_ratio, qcoeff); + double ref_rate = -log2(prob); + EXPECT_DOUBLE_EQ(rate, ref_rate); + } +} + +TEST(TplModelTest, TransformCoeffEntropyTest2) { + // Check the consistency between av1_estimate_coeff_entropy(), laplace_prob() + // and av1_laplace_entropy() + double b = 1; + double q_step = 1; + double zero_bin_ratio = 2; + double est_expected_rate = 0; + for (int qcoeff = -20; qcoeff < 20; ++qcoeff) { + double rate = av1_estimate_coeff_entropy(q_step, b, zero_bin_ratio, qcoeff); + double prob = laplace_prob(q_step, b, zero_bin_ratio, qcoeff); + est_expected_rate += prob * rate; + } + double expected_rate = av1_laplace_entropy(q_step, b, zero_bin_ratio); + EXPECT_NEAR(expected_rate, est_expected_rate, 0.001); +} + +} // namespace