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