Add the motion vector unit test
This unit test was ported from VP9. To prevent the motion vector out of
range bug, added a motion vector unit test. In the 4k video encoding,
always forced to use extreme motion vectors and also encouraged to use
INTER modes. In the decoding, checked if the motion vector was valid,
and also checked the encoder/decoder mismatch.
Change-Id: I1c72ea7c32a3cec9c67f1bbdc168e60507e57516
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 2e0bbac..debec21 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -523,6 +523,13 @@
* Experiment: EXT_TILE
*/
AV1E_SET_TILE_ENCODING_MODE,
+
+ /*!\brief Codec control function to enable the extreme motion vector unit test
+ * in AV1. Please note that this is only used in motion vector unit test.
+ *
+ * 0 : off, 1 : MAX_EXTREME_MV, 2 : MIN_EXTREME_MV
+ */
+ AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST,
};
/*!\brief aom 1-D scaling mode
@@ -730,6 +737,10 @@
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ENCODING_MODE, unsigned int)
#define AOM_CTRL_AV1E_SET_TILE_ENCODING_MODE
+
+AOM_CTRL_USE_TYPE(AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, unsigned int)
+#define AOM_CTRL_AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST
+
/*!\endcond */
/*! @} - end defgroup aom_encoder */
#ifdef __cplusplus
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 1d976d3..d4832a1 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -81,6 +81,8 @@
#if CONFIG_EXT_TILE
unsigned int tile_encoding_mode;
#endif // CONFIG_EXT_TILE
+
+ unsigned int motion_vector_unit_test;
};
static struct av1_extracfg default_extra_cfg = {
@@ -146,6 +148,8 @@
#if CONFIG_EXT_TILE
0, // Tile encoding mode is TILE_NORMAL by default.
#endif // CONFIG_EXT_TILE
+
+ 0, // motion_vector_unit_test
};
struct aom_codec_alg_priv {
@@ -259,6 +263,7 @@
"kf_min_dist not supported in auto mode, use 0 "
"or kf_max_dist instead.");
+ RANGE_CHECK_HI(extra_cfg, motion_vector_unit_test, 2);
RANGE_CHECK_HI(extra_cfg, enable_auto_alt_ref, 2);
#if CONFIG_EXT_REFS
RANGE_CHECK_HI(extra_cfg, enable_auto_bwd_ref, 2);
@@ -559,6 +564,7 @@
oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
+ oxcf->motion_vector_unit_test = extra_cfg->motion_vector_unit_test;
/*
printf("Current AV1 Settings: \n");
printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
@@ -887,6 +893,14 @@
return update_extra_cfg(ctx, &extra_cfg);
}
+static aom_codec_err_t ctrl_enable_motion_vector_unit_test(
+ aom_codec_alg_priv_t *ctx, va_list args) {
+ struct av1_extracfg extra_cfg = ctx->extra_cfg;
+ extra_cfg.motion_vector_unit_test =
+ CAST(AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, args);
+ return update_extra_cfg(ctx, &extra_cfg);
+}
+
static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx,
aom_codec_priv_enc_mr_cfg_t *data) {
aom_codec_err_t res = AOM_CODEC_OK;
@@ -1492,6 +1506,7 @@
#if CONFIG_EXT_TILE
{ AV1E_SET_TILE_ENCODING_MODE, ctrl_set_tile_encoding_mode },
#endif // CONFIG_EXT_TILE
+ { AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test },
// Getters
{ AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer },
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index d746264..fe37672 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -280,6 +280,8 @@
#if CONFIG_EXT_TILE
unsigned int tile_encoding_mode;
#endif // CONFIG_EXT_TILE
+
+ unsigned int motion_vector_unit_test;
} AV1EncoderConfig;
static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) {
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index f5745f2..ae8f04e 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -21,6 +21,7 @@
#include "aom_ports/mem.h"
#include "av1/common/common.h"
+#include "av1/common/mvref_common.h"
#include "av1/common/reconinter.h"
#include "av1/encoder/encoder.h"
@@ -3413,3 +3414,78 @@
return bestsme;
}
#endif // CONFIG_MOTION_VAR
+
+// Note(yunqingwang): The following 2 functions are only used in the motion
+// vector unit test, which return extreme motion vectors allowed by the MV
+// limits.
+#define COMMON_MV_TEST \
+ SETUP_SUBPEL_SEARCH; \
+ \
+ (void)error_per_bit; \
+ (void)vfp; \
+ (void)src_address; \
+ (void)src_stride; \
+ (void)y; \
+ (void)y_stride; \
+ (void)second_pred; \
+ (void)w; \
+ (void)h; \
+ (void)use_upsampled_ref; \
+ (void)offset; \
+ (void)mvjcost; \
+ (void)mvcost; \
+ (void)sse1; \
+ (void)distortion; \
+ \
+ (void)halfiters; \
+ (void)quarteriters; \
+ (void)eighthiters; \
+ (void)whichdir; \
+ (void)forced_stop; \
+ (void)hstep; \
+ \
+ (void)tr; \
+ (void)tc; \
+ (void)sse; \
+ (void)thismse; \
+ (void)cost_list;
+// Return the maximum MV.
+int av1_return_max_sub_pixel_mv(MACROBLOCK *x, const MV *ref_mv, int allow_hp,
+ int error_per_bit,
+ const aom_variance_fn_ptr_t *vfp,
+ int forced_stop, int iters_per_step,
+ int *cost_list, int *mvjcost, int *mvcost[2],
+ int *distortion, unsigned int *sse1,
+ const uint8_t *second_pred, int w, int h,
+ int use_upsampled_ref) {
+ COMMON_MV_TEST;
+ (void)minr;
+ (void)minc;
+ bestmv->row = maxr;
+ bestmv->col = maxc;
+ besterr = 0;
+ // In the sub-pel motion search, if hp is not used, then the last bit of mv
+ // has to be 0.
+ lower_mv_precision(bestmv, allow_hp);
+ return besterr;
+}
+// Return the minimum MV.
+int av1_return_min_sub_pixel_mv(MACROBLOCK *x, const MV *ref_mv, int allow_hp,
+ int error_per_bit,
+ const aom_variance_fn_ptr_t *vfp,
+ int forced_stop, int iters_per_step,
+ int *cost_list, int *mvjcost, int *mvcost[2],
+ int *distortion, unsigned int *sse1,
+ const uint8_t *second_pred, int w, int h,
+ int use_upsampled_ref) {
+ COMMON_MV_TEST;
+ (void)maxr;
+ (void)maxc;
+ bestmv->row = minr;
+ bestmv->col = minc;
+ besterr = 0;
+ // In the sub-pel motion search, if hp is not used, then the last bit of mv
+ // has to be 0.
+ lower_mv_precision(bestmv, allow_hp);
+ return besterr;
+}
diff --git a/av1/encoder/mcomp.h b/av1/encoder/mcomp.h
index 780b2d5..8465860 100644
--- a/av1/encoder/mcomp.h
+++ b/av1/encoder/mcomp.h
@@ -98,6 +98,8 @@
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned;
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_more;
extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_evenmore;
+extern fractional_mv_step_fp av1_return_max_sub_pixel_mv;
+extern fractional_mv_step_fp av1_return_min_sub_pixel_mv;
typedef int (*av1_full_search_fn_t)(const MACROBLOCK *x, const MV *ref_mv,
int sad_per_bit, int distance,
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index d33504b..1015542 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -10019,6 +10019,9 @@
if (best_rd < mode_threshold[mode_index]) continue;
+ // This is only used in motion vector unit test.
+ if (cpi->oxcf.motion_vector_unit_test && ref_frame == INTRA_FRAME) continue;
+
comp_pred = second_ref_frame > INTRA_FRAME;
if (comp_pred) {
if (!cpi->allow_comp_inter_inter) continue;
@@ -11742,6 +11745,9 @@
tile_data->thresh_freq_fact[bsize][ref_index]))
continue;
+ // This is only used in motion vector unit test.
+ if (cpi->oxcf.motion_vector_unit_test && ref_frame == INTRA_FRAME) continue;
+
comp_pred = second_ref_frame > INTRA_FRAME;
if (comp_pred) {
if (!cpi->allow_comp_inter_inter) continue;
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 3bf2df0..89d2f50 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -322,6 +322,12 @@
rd->thresh_mult_sub8x8[i] = INT_MAX;
}
}
+
+ // This is only used in motion vector unit test.
+ if (cpi->oxcf.motion_vector_unit_test == 1)
+ cpi->find_fractional_mv_step = av1_return_max_sub_pixel_mv;
+ else if (cpi->oxcf.motion_vector_unit_test == 2)
+ cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
}
void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
@@ -472,4 +478,10 @@
if (!cpi->oxcf.frame_periodic_boost) {
sf->max_delta_qindex = 0;
}
+
+ // This is only used in motion vector unit test.
+ if (cpi->oxcf.motion_vector_unit_test == 1)
+ cpi->find_fractional_mv_step = av1_return_max_sub_pixel_mv;
+ else if (cpi->oxcf.motion_vector_unit_test == 2)
+ cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
}
diff --git a/test/motion_vector_test.cc b/test/motion_vector_test.cc
new file mode 100644
index 0000000..7df7575
--- /dev/null
+++ b/test/motion_vector_test.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2017, 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 "third_party/googletest/src/googletest/include/gtest/gtest.h"
+
+#include "test/codec_factory.h"
+#include "test/encode_test_driver.h"
+#include "test/util.h"
+#include "test/yuv_video_source.h"
+
+namespace {
+#define MAX_EXTREME_MV 1
+#define MIN_EXTREME_MV 2
+
+// Encoding modes
+const libaom_test::TestMode kEncodingModeVectors[] = {
+ ::libaom_test::kTwoPassGood, ::libaom_test::kOnePassGood,
+};
+
+// Encoding speeds
+const int kCpuUsedVectors[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+
+// MV test modes: 1 - always use maximum MV; 2 - always use minimum MV.
+const int kMVTestModes[] = { MAX_EXTREME_MV, MIN_EXTREME_MV };
+
+class MotionVectorTestLarge
+ : public ::libaom_test::EncoderTest,
+ public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int,
+ int> {
+ protected:
+ MotionVectorTestLarge()
+ : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
+ cpu_used_(GET_PARAM(2)), mv_test_mode_(GET_PARAM(3)) {}
+
+ virtual ~MotionVectorTestLarge() {}
+
+ virtual void SetUp() {
+ InitializeConfig();
+ SetMode(encoding_mode_);
+ if (encoding_mode_ != ::libaom_test::kRealTime) {
+ cfg_.g_lag_in_frames = 3;
+ cfg_.rc_end_usage = AOM_VBR;
+ } else {
+ cfg_.g_lag_in_frames = 0;
+ cfg_.rc_end_usage = AOM_CBR;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 600;
+ }
+ }
+
+ virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
+ ::libaom_test::Encoder *encoder) {
+ if (video->frame() == 1) {
+ encoder->Control(AOME_SET_CPUUSED, cpu_used_);
+ encoder->Control(AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, mv_test_mode_);
+ if (encoding_mode_ != ::libaom_test::kRealTime) {
+ encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
+ encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
+ encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
+ }
+ }
+ }
+
+ libaom_test::TestMode encoding_mode_;
+ int cpu_used_;
+ int mv_test_mode_;
+};
+
+TEST_P(MotionVectorTestLarge, OverallTest) {
+ cfg_.rc_target_bitrate = 24000;
+ cfg_.g_profile = 0;
+ init_flags_ = AOM_CODEC_USE_PSNR;
+
+ testing::internal::scoped_ptr<libaom_test::VideoSource> video;
+ video.reset(new libaom_test::YUVVideoSource(
+ "niklas_640_480_30.yuv", AOM_IMG_FMT_I420, 3840, 2160, // 2048, 1080,
+ 30, 1, 0, 5));
+
+ ASSERT_TRUE(video.get() != NULL);
+ ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
+}
+
+AV1_INSTANTIATE_TEST_CASE(MotionVectorTestLarge,
+ ::testing::ValuesIn(kEncodingModeVectors),
+ ::testing::ValuesIn(kCpuUsedVectors),
+ ::testing::ValuesIn(kMVTestModes));
+} // namespace
diff --git a/test/test-data.mk b/test/test-data.mk
index dc877af..168144a 100644
--- a/test/test-data.mk
+++ b/test/test-data.mk
@@ -22,6 +22,7 @@
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += niklas_1280_720_30.y4m
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += rush_hour_444.y4m
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += screendata.y4m
+LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += niklas_640_480_30.yuv
ifeq ($(CONFIG_DECODE_PERF_TESTS),yes)
# Encode / Decode test
@@ -33,7 +34,6 @@
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += kirland_640_480_30.yuv
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += macmarcomoving_640_480_30.yuv
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += macmarcostationary_640_480_30.yuv
-LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += niklas_640_480_30.yuv
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += niklas_1280_720_30.yuv
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += tacomanarrows_640_480_30.yuv
LIBAOM_TEST_DATA-$(CONFIG_AV1_ENCODER) += tacomasmallcameramovement_640_480_30.yuv
diff --git a/test/test.mk b/test/test.mk
index b9bbb9d..fb0ab37 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -113,6 +113,7 @@
LIBAOM_TEST_SRCS-yes += superframe_test.cc
LIBAOM_TEST_SRCS-yes += tile_independence_test.cc
LIBAOM_TEST_SRCS-yes += ethread_test.cc
+LIBAOM_TEST_SRCS-yes += motion_vector_test.cc
ifneq ($(CONFIG_ANS),yes)
LIBAOM_TEST_SRCS-yes += binary_codes_test.cc
endif