From fb515ea77bc5d1d724879967787ff5db36979625 Mon Sep 17 00:00:00 2001 From: Roy Tam Date: Fri, 29 Mar 2019 21:53:07 +0800 Subject: [PATCH] update libaom to rev 5bdd95475e07ac8641114cb139105b8d734a1b60 (without moz.build and aom_ports/aom_once.h) --- media/libaom/README_MCP | 2 +- .../config/generic/config/aom_config.asm | 6 +- .../libaom/config/generic/config/aom_config.h | 6 +- .../config/generic/config/aom_scale_rtcd.h | 3 + .../config/linux/arm/config/aom_config.asm | 6 +- .../config/linux/arm/config/aom_config.h | 6 +- .../config/linux/arm/config/aom_scale_rtcd.h | 3 + .../config/linux/ia32/config/aom_config.asm | 6 +- .../config/linux/ia32/config/aom_config.h | 6 +- .../config/linux/ia32/config/aom_scale_rtcd.h | 3 + .../config/linux/ia32/config/av1_rtcd.h | 4 - .../config/linux/x64/config/aom_config.asm | 6 +- .../config/linux/x64/config/aom_config.h | 6 +- .../config/linux/x64/config/aom_scale_rtcd.h | 3 + .../libaom/config/linux/x64/config/av1_rtcd.h | 4 - .../config/mac/x64/config/aom_config.asm | 6 +- .../libaom/config/mac/x64/config/aom_config.h | 6 +- .../config/mac/x64/config/aom_scale_rtcd.h | 3 + media/libaom/config/mac/x64/config/av1_rtcd.h | 4 - .../config/win/ia32/config/aom_config.asm | 6 +- .../config/win/ia32/config/aom_config.h | 6 +- .../config/win/ia32/config/aom_scale_rtcd.h | 3 + .../libaom/config/win/ia32/config/av1_rtcd.h | 4 - .../config/win/mingw32/config/aom_config.asm | 6 +- .../config/win/mingw32/config/aom_config.h | 6 +- .../win/mingw32/config/aom_scale_rtcd.h | 3 + .../config/win/mingw32/config/av1_rtcd.h | 4 - .../config/win/mingw64/config/aom_config.asm | 6 +- .../config/win/mingw64/config/aom_config.h | 6 +- .../win/mingw64/config/aom_scale_rtcd.h | 3 + .../config/win/mingw64/config/av1_rtcd.h | 4 - .../config/win/x64/config/aom_config.asm | 6 +- .../libaom/config/win/x64/config/aom_config.h | 6 +- .../config/win/x64/config/aom_scale_rtcd.h | 3 + media/libaom/config/win/x64/config/av1_rtcd.h | 4 - third_party/aom/CMakeLists.txt | 5 +- third_party/aom/aom/aom_encoder.h | 8 +- third_party/aom/aom/aomcx.h | 248 +- third_party/aom/aom_dsp/aom_dsp.cmake | 3 + third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl | 59 +- third_party/aom/aom_dsp/avg.c | 79 + third_party/aom/aom_dsp/bitreader_buffer.c | 4 +- third_party/aom/aom_dsp/grain_synthesis.c | 3 +- third_party/aom/aom_dsp/quantize.c | 78 +- .../aom/aom_dsp/x86/adaptive_quantize_sse2.c | 421 +++ third_party/aom/aom_dsp/x86/avg_intrin_sse2.c | 123 + third_party/aom/aom_dsp/x86/convolve_avx2.h | 249 +- .../aom_dsp/x86/highbd_intrapred_sse2_asm.asm | 259 -- .../aom_dsp/x86/highbd_quantize_intrin_sse2.c | 58 + .../aom/aom_dsp/x86/highbd_variance_sse2.c | 161 +- third_party/aom/aom_dsp/x86/intrapred_avx2.c | 911 ++++-- .../aom/aom_dsp/x86/intrapred_sse2_asm.asm | 625 ---- third_party/aom/aom_dsp/x86/loopfilter_sse2.c | 4 +- third_party/aom/aom_dsp/x86/quantize_x86.h | 48 + .../aom/aom_dsp/x86/ssim_opt_x86_64.asm | 222 -- .../aom/aom_dsp/x86/txfm_common_avx2.h | 90 + third_party/aom/aom_scale/aom_scale.cmake | 4 + third_party/aom/aom_scale/aom_scale_rtcd.pl | 2 + .../aom/aom_scale/generic/yv12config.c | 142 +- .../aom/aom_scale/generic/yv12extend.c | 25 + third_party/aom/aom_scale/yv12config.h | 9 + third_party/aom/apps/aomdec.c | 2 +- third_party/aom/apps/aomenc.c | 176 +- third_party/aom/av1/av1.cmake | 35 +- third_party/aom/av1/av1_cx_iface.c | 312 +- third_party/aom/av1/av1_dx_iface.c | 72 +- third_party/aom/av1/common/av1_inv_txfm2d.c | 4 +- third_party/aom/av1/common/av1_rtcd_defs.pl | 23 +- third_party/aom/av1/common/av1_txfm.h | 2 + third_party/aom/av1/common/blockd.h | 5 - third_party/aom/av1/common/cdef.c | 1 - third_party/aom/av1/common/cdef_block.c | 4 +- third_party/aom/av1/common/cdef_block.h | 1 - third_party/aom/av1/common/entropy.c | 2 +- third_party/aom/av1/common/entropymode.c | 22 +- third_party/aom/av1/common/entropymode.h | 3 +- third_party/aom/av1/common/enums.h | 42 +- third_party/aom/av1/common/mvref_common.c | 28 +- third_party/aom/av1/common/mvref_common.h | 6 +- third_party/aom/av1/common/onyxc_int.h | 52 +- third_party/aom/av1/common/pred_common.h | 6 +- third_party/aom/av1/common/reconinter.h | 8 +- third_party/aom/av1/common/restoration.h | 2 +- third_party/aom/av1/common/tile_common.c | 23 + third_party/aom/av1/common/tile_common.h | 3 + .../aom/av1/common/x86/av1_inv_txfm_ssse3.c | 14 +- .../aom/av1/common/x86/convolve_2d_avx2.c | 132 +- .../aom/av1/common/x86/convolve_avx2.c | 484 ++- .../aom/av1/common/x86/highbd_inv_txfm_sse4.c | 18 +- .../aom/av1/common/x86/jnt_convolve_avx2.c | 747 +++-- .../aom/av1/common/x86/wiener_convolve_avx2.c | 360 ++- third_party/aom/av1/decoder/decodeframe.c | 36 +- third_party/aom/av1/decoder/decodemv.c | 17 +- third_party/aom/av1/decoder/decoder.h | 2 +- third_party/aom/av1/decoder/dthread.c | 192 -- third_party/aom/av1/decoder/inspection.c | 3 + third_party/aom/av1/decoder/inspection.h | 3 + third_party/aom/av1/decoder/obu.c | 21 +- .../aom/av1/encoder/aq_cyclicrefresh.c | 189 +- .../aom/av1/encoder/aq_cyclicrefresh.h | 7 - third_party/aom/av1/encoder/av1_quantize.c | 10 +- third_party/aom/av1/encoder/av1_quantize.h | 3 + third_party/aom/av1/encoder/bitstream.c | 114 +- third_party/aom/av1/encoder/bitstream.h | 9 +- third_party/aom/av1/encoder/block.h | 27 +- third_party/aom/av1/encoder/context_tree.h | 16 - third_party/aom/av1/encoder/encode_strategy.c | 827 +++-- third_party/aom/av1/encoder/encode_strategy.h | 8 +- third_party/aom/av1/encoder/encodeframe.c | 2397 +++++--------- third_party/aom/av1/encoder/encodemb.c | 49 +- third_party/aom/av1/encoder/encoder.c | 1133 +++---- third_party/aom/av1/encoder/encoder.h | 321 +- third_party/aom/av1/encoder/encodetxb.c | 124 +- third_party/aom/av1/encoder/encodetxb.h | 2 +- third_party/aom/av1/encoder/ethread.c | 60 +- third_party/aom/av1/encoder/firstpass.c | 2364 +------------- third_party/aom/av1/encoder/firstpass.h | 128 +- third_party/aom/av1/encoder/global_motion.c | 29 +- third_party/aom/av1/encoder/global_motion.h | 6 + third_party/aom/av1/encoder/gop_structure.c | 192 ++ third_party/aom/av1/encoder/gop_structure.h | 36 + third_party/aom/av1/encoder/hash_motion.c | 3 +- third_party/aom/av1/encoder/level.c | 599 ++++ third_party/aom/av1/encoder/level.h | 76 + third_party/aom/av1/encoder/lookahead.c | 19 +- third_party/aom/av1/encoder/lookahead.h | 2 +- third_party/aom/av1/encoder/mcomp.c | 361 ++- third_party/aom/av1/encoder/mcomp.h | 25 +- .../aom/av1/encoder/partition_model_weights.h | 2782 +++++++++++------ .../aom/av1/encoder/partition_strategy.c | 722 +++++ .../aom/av1/encoder/partition_strategy.h | 154 + third_party/aom/av1/encoder/pass2_strategy.c | 1787 +++++++++++ third_party/aom/av1/encoder/pass2_strategy.h | 34 + third_party/aom/av1/encoder/picklpf.c | 14 +- third_party/aom/av1/encoder/pickrst.c | 24 +- third_party/aom/av1/encoder/ratectrl.c | 413 +-- third_party/aom/av1/encoder/ratectrl.h | 58 +- third_party/aom/av1/encoder/rd.c | 702 +---- third_party/aom/av1/encoder/rd.h | 257 -- third_party/aom/av1/encoder/rdopt.c | 2640 +++++++++++----- third_party/aom/av1/encoder/rdopt.h | 17 +- third_party/aom/av1/encoder/speed_features.c | 375 ++- third_party/aom/av1/encoder/speed_features.h | 99 +- third_party/aom/av1/encoder/temporal_filter.c | 168 +- third_party/aom/av1/encoder/tpl_model.c | 31 +- third_party/aom/av1/encoder/var_based_part.c | 778 +++++ third_party/aom/av1/encoder/var_based_part.h | 37 + .../aom/av1/encoder/x86/av1_fwd_txfm2d_avx2.c | 798 ++++- .../aom/av1/encoder/x86/corner_match_avx2.c | 3 - .../x86/highbd_block_error_intrin_avx2.c | 62 + .../encoder/x86/highbd_temporal_filter_sse4.c | 954 ++++++ .../x86/temporal_filter_apply_sse2.asm | 218 -- .../encoder/x86/temporal_filter_constants.h | 401 +++ .../av1/encoder/x86/temporal_filter_sse4.c | 1006 ++++++ .../aom/build/cmake/aom_config_defaults.cmake | 9 +- .../cmake/toolchains/armv7-linux-gcc.cmake | 9 +- third_party/aom/examples/inspect.c | 44 +- third_party/aom/test/av1_fwd_txfm2d_test.cc | 66 +- third_party/aom/test/av1_highbd_iht_test.cc | 3 +- third_party/aom/test/dr_prediction_test.cc | 39 +- third_party/aom/test/edge_detect_test.cc | 11 +- third_party/aom/test/encode_api_test.cc | 2 +- third_party/aom/test/error_block_test.cc | 77 + third_party/aom/test/fwd_kf_test.cc | 110 + .../aom/test/gf_max_pyr_height_test.cc | 115 + .../aom/test/hiprec_convolve_test_util.cc | 4 +- third_party/aom/test/horz_superres_test.cc | 178 +- third_party/aom/test/level_test.cc | 108 + third_party/aom/test/quantize_func_test.cc | 66 +- third_party/aom/test/resize_test.cc | 1 + third_party/aom/test/rt_end_to_end_test.cc | 141 + third_party/aom/test/test-data.sha1 | 6 + third_party/aom/test/test.cmake | 7 +- third_party/aom/test/test_data_util.cmake | 6 + third_party/aom/test/test_vectors.cc | 356 ++- third_party/aom/test/variance_test.cc | 47 +- .../aom/test/yuv_temporal_filter_test.cc | 726 +++++ 177 files changed, 21038 insertions(+), 11631 deletions(-) create mode 100644 third_party/aom/aom_dsp/x86/adaptive_quantize_sse2.c delete mode 100644 third_party/aom/aom_dsp/x86/highbd_intrapred_sse2_asm.asm delete mode 100644 third_party/aom/aom_dsp/x86/intrapred_sse2_asm.asm delete mode 100644 third_party/aom/aom_dsp/x86/ssim_opt_x86_64.asm delete mode 100644 third_party/aom/av1/decoder/dthread.c create mode 100644 third_party/aom/av1/encoder/gop_structure.c create mode 100644 third_party/aom/av1/encoder/gop_structure.h create mode 100644 third_party/aom/av1/encoder/level.c create mode 100644 third_party/aom/av1/encoder/level.h create mode 100644 third_party/aom/av1/encoder/partition_strategy.c create mode 100644 third_party/aom/av1/encoder/partition_strategy.h create mode 100644 third_party/aom/av1/encoder/pass2_strategy.c create mode 100644 third_party/aom/av1/encoder/pass2_strategy.h create mode 100644 third_party/aom/av1/encoder/var_based_part.c create mode 100644 third_party/aom/av1/encoder/var_based_part.h create mode 100644 third_party/aom/av1/encoder/x86/highbd_block_error_intrin_avx2.c create mode 100644 third_party/aom/av1/encoder/x86/highbd_temporal_filter_sse4.c delete mode 100644 third_party/aom/av1/encoder/x86/temporal_filter_apply_sse2.asm create mode 100644 third_party/aom/av1/encoder/x86/temporal_filter_constants.h create mode 100644 third_party/aom/av1/encoder/x86/temporal_filter_sse4.c create mode 100644 third_party/aom/test/fwd_kf_test.cc create mode 100644 third_party/aom/test/gf_max_pyr_height_test.cc create mode 100644 third_party/aom/test/level_test.cc create mode 100644 third_party/aom/test/rt_end_to_end_test.cc create mode 100644 third_party/aom/test/yuv_temporal_filter_test.cc diff --git a/media/libaom/README_MCP b/media/libaom/README_MCP index bab18e4b5a..59cf02f240 100644 --- a/media/libaom/README_MCP +++ b/media/libaom/README_MCP @@ -10,4 +10,4 @@ The upstream aom git repository is: https://aomedia.googlesource.com/aom -The git commit ID used was 0ec86ac7ae1e32a7e70410fa4972a655ec3670a4. +The git commit ID used was 5bdd95475e07ac8641114cb139105b8d734a1b60. diff --git a/media/libaom/config/generic/config/aom_config.asm b/media/libaom/config/generic/config/aom_config.asm index a236ca9dd2..a56b320139 100644 --- a/media/libaom/config/generic/config/aom_config.asm +++ b/media/libaom/config/generic/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 0 ARCH_X86_64 equ 0 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/generic/config/aom_config.h b/media/libaom/config/generic/config/aom_config.h index 3b3798a451..f9c98d6070 100644 --- a/media/libaom/config/generic/config/aom_config.h +++ b/media/libaom/config/generic/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/generic/config/aom_scale_rtcd.h b/media/libaom/config/generic/config/aom_scale_rtcd.h index 8b92a2d57f..46b018d86a 100644 --- a/media/libaom/config/generic/config/aom_scale_rtcd.h +++ b/media/libaom/config/generic/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #include "config/aom_config.h" diff --git a/media/libaom/config/linux/arm/config/aom_config.asm b/media/libaom/config/linux/arm/config/aom_config.asm index c680ea1ba7..51363acfb2 100644 --- a/media/libaom/config/linux/arm/config/aom_config.asm +++ b/media/libaom/config/linux/arm/config/aom_config.asm @@ -14,7 +14,8 @@ .equ ARCH_PPC, 0 .equ ARCH_X86, 0 .equ ARCH_X86_64, 0 -.equ CONFIG_2PASS_PARTITION_SEARCH_LVL, 1 +.equ CONFIG_2PASS_PARTITION_SEARCH_LVL_END, 3 +.equ CONFIG_2PASS_PARTITION_SEARCH_LVL_START, 1 .equ CONFIG_ACCOUNTING, 0 .equ CONFIG_ANALYZER, 0 .equ CONFIG_AV1_DECODER, 1 @@ -22,6 +23,7 @@ .equ CONFIG_BIG_ENDIAN, 0 .equ CONFIG_BITSTREAM_DEBUG, 0 .equ CONFIG_COEFFICIENT_RANGE_CHECKING, 0 +.equ CONFIG_COLLECT_COMPONENT_TIMING, 0 .equ CONFIG_COLLECT_PARTITION_STATS, 0 .equ CONFIG_COLLECT_RD_STATS, 0 .equ CONFIG_DEBUG, 0 @@ -30,7 +32,6 @@ .equ CONFIG_DIST_8X8, 0 .equ CONFIG_ENTROPY_STATS, 0 .equ CONFIG_FILEOPTIONS, 1 -.equ CONFIG_FP_MB_STATS, 0 .equ CONFIG_GCC, 1 .equ CONFIG_GCOV, 0 .equ CONFIG_GPROF, 0 @@ -43,7 +44,6 @@ .equ CONFIG_MISMATCH_DEBUG, 0 .equ CONFIG_MULTITHREAD, 1 .equ CONFIG_NORMAL_TILE_MODE, 0 -.equ CONFIG_ONE_PASS_SVM, 0 .equ CONFIG_OS_SUPPORT, 1 .equ CONFIG_PIC, 1 .equ CONFIG_RD_DEBUG, 0 diff --git a/media/libaom/config/linux/arm/config/aom_config.h b/media/libaom/config/linux/arm/config/aom_config.h index ffc5188369..ea62536159 100644 --- a/media/libaom/config/linux/arm/config/aom_config.h +++ b/media/libaom/config/linux/arm/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 1 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/linux/arm/config/aom_scale_rtcd.h b/media/libaom/config/linux/arm/config/aom_scale_rtcd.h index 7260bd372f..067ddb4928 100644 --- a/media/libaom/config/linux/arm/config/aom_scale_rtcd.h +++ b/media/libaom/config/linux/arm/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #include "config/aom_config.h" diff --git a/media/libaom/config/linux/ia32/config/aom_config.asm b/media/libaom/config/linux/ia32/config/aom_config.asm index d037bc4231..0e8d2f295c 100644 --- a/media/libaom/config/linux/ia32/config/aom_config.asm +++ b/media/libaom/config/linux/ia32/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 1 ARCH_X86_64 equ 0 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 1 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/linux/ia32/config/aom_config.h b/media/libaom/config/linux/ia32/config/aom_config.h index 67201081b2..0fbfda50a1 100644 --- a/media/libaom/config/linux/ia32/config/aom_config.h +++ b/media/libaom/config/linux/ia32/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 1 #define ARCH_X86_64 0 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 1 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/linux/ia32/config/aom_scale_rtcd.h b/media/libaom/config/linux/ia32/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/linux/ia32/config/aom_scale_rtcd.h +++ b/media/libaom/config/linux/ia32/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/linux/ia32/config/av1_rtcd.h b/media/libaom/config/linux/ia32/config/av1_rtcd.h index 8e69b643ef..ea1cd37366 100644 --- a/media/libaom/config/linux/ia32/config/av1_rtcd.h +++ b/media/libaom/config/linux/ia32/config/av1_rtcd.h @@ -222,7 +222,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -325,7 +324,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -532,7 +530,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -556,7 +553,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/media/libaom/config/linux/x64/config/aom_config.asm b/media/libaom/config/linux/x64/config/aom_config.asm index 294d0294b6..dfe9f61a31 100644 --- a/media/libaom/config/linux/x64/config/aom_config.asm +++ b/media/libaom/config/linux/x64/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 0 ARCH_X86_64 equ 1 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/linux/x64/config/aom_config.h b/media/libaom/config/linux/x64/config/aom_config.h index ffff5abe6a..5407b2b76a 100644 --- a/media/libaom/config/linux/x64/config/aom_config.h +++ b/media/libaom/config/linux/x64/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/linux/x64/config/aom_scale_rtcd.h b/media/libaom/config/linux/x64/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/linux/x64/config/aom_scale_rtcd.h +++ b/media/libaom/config/linux/x64/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/linux/x64/config/av1_rtcd.h b/media/libaom/config/linux/x64/config/av1_rtcd.h index 80bacb8dd5..c4954fef53 100644 --- a/media/libaom/config/linux/x64/config/av1_rtcd.h +++ b/media/libaom/config/linux/x64/config/av1_rtcd.h @@ -225,7 +225,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -328,7 +327,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -526,7 +524,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -550,7 +547,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/media/libaom/config/mac/x64/config/aom_config.asm b/media/libaom/config/mac/x64/config/aom_config.asm index 294d0294b6..dfe9f61a31 100644 --- a/media/libaom/config/mac/x64/config/aom_config.asm +++ b/media/libaom/config/mac/x64/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 0 ARCH_X86_64 equ 1 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/mac/x64/config/aom_config.h b/media/libaom/config/mac/x64/config/aom_config.h index ffff5abe6a..5407b2b76a 100644 --- a/media/libaom/config/mac/x64/config/aom_config.h +++ b/media/libaom/config/mac/x64/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/mac/x64/config/aom_scale_rtcd.h b/media/libaom/config/mac/x64/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/mac/x64/config/aom_scale_rtcd.h +++ b/media/libaom/config/mac/x64/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/mac/x64/config/av1_rtcd.h b/media/libaom/config/mac/x64/config/av1_rtcd.h index 80bacb8dd5..c4954fef53 100644 --- a/media/libaom/config/mac/x64/config/av1_rtcd.h +++ b/media/libaom/config/mac/x64/config/av1_rtcd.h @@ -225,7 +225,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -328,7 +327,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -526,7 +524,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -550,7 +547,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/media/libaom/config/win/ia32/config/aom_config.asm b/media/libaom/config/win/ia32/config/aom_config.asm index b3a8c2d596..9c316e6fcf 100644 --- a/media/libaom/config/win/ia32/config/aom_config.asm +++ b/media/libaom/config/win/ia32/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 1 ARCH_X86_64 equ 0 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/win/ia32/config/aom_config.h b/media/libaom/config/win/ia32/config/aom_config.h index 394c9d574e..fa665e84c5 100644 --- a/media/libaom/config/win/ia32/config/aom_config.h +++ b/media/libaom/config/win/ia32/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 1 #define ARCH_X86_64 0 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/win/ia32/config/aom_scale_rtcd.h b/media/libaom/config/win/ia32/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/win/ia32/config/aom_scale_rtcd.h +++ b/media/libaom/config/win/ia32/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/win/ia32/config/av1_rtcd.h b/media/libaom/config/win/ia32/config/av1_rtcd.h index 8e69b643ef..ea1cd37366 100644 --- a/media/libaom/config/win/ia32/config/av1_rtcd.h +++ b/media/libaom/config/win/ia32/config/av1_rtcd.h @@ -222,7 +222,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -325,7 +324,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -532,7 +530,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -556,7 +553,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/media/libaom/config/win/mingw32/config/aom_config.asm b/media/libaom/config/win/mingw32/config/aom_config.asm index b3a8c2d596..9c316e6fcf 100644 --- a/media/libaom/config/win/mingw32/config/aom_config.asm +++ b/media/libaom/config/win/mingw32/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 1 ARCH_X86_64 equ 0 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/win/mingw32/config/aom_config.h b/media/libaom/config/win/mingw32/config/aom_config.h index 394c9d574e..fa665e84c5 100644 --- a/media/libaom/config/win/mingw32/config/aom_config.h +++ b/media/libaom/config/win/mingw32/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 1 #define ARCH_X86_64 0 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/win/mingw32/config/aom_scale_rtcd.h b/media/libaom/config/win/mingw32/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/win/mingw32/config/aom_scale_rtcd.h +++ b/media/libaom/config/win/mingw32/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/win/mingw32/config/av1_rtcd.h b/media/libaom/config/win/mingw32/config/av1_rtcd.h index 8e69b643ef..ea1cd37366 100644 --- a/media/libaom/config/win/mingw32/config/av1_rtcd.h +++ b/media/libaom/config/win/mingw32/config/av1_rtcd.h @@ -222,7 +222,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -325,7 +324,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -532,7 +530,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -556,7 +553,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/media/libaom/config/win/mingw64/config/aom_config.asm b/media/libaom/config/win/mingw64/config/aom_config.asm index 294d0294b6..dfe9f61a31 100644 --- a/media/libaom/config/win/mingw64/config/aom_config.asm +++ b/media/libaom/config/win/mingw64/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 0 ARCH_X86_64 equ 1 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/win/mingw64/config/aom_config.h b/media/libaom/config/win/mingw64/config/aom_config.h index ffff5abe6a..5407b2b76a 100644 --- a/media/libaom/config/win/mingw64/config/aom_config.h +++ b/media/libaom/config/win/mingw64/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/win/mingw64/config/aom_scale_rtcd.h b/media/libaom/config/win/mingw64/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/win/mingw64/config/aom_scale_rtcd.h +++ b/media/libaom/config/win/mingw64/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/win/mingw64/config/av1_rtcd.h b/media/libaom/config/win/mingw64/config/av1_rtcd.h index 80bacb8dd5..c4954fef53 100644 --- a/media/libaom/config/win/mingw64/config/av1_rtcd.h +++ b/media/libaom/config/win/mingw64/config/av1_rtcd.h @@ -225,7 +225,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -328,7 +327,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -526,7 +524,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -550,7 +547,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/media/libaom/config/win/x64/config/aom_config.asm b/media/libaom/config/win/x64/config/aom_config.asm index 294d0294b6..dfe9f61a31 100644 --- a/media/libaom/config/win/x64/config/aom_config.asm +++ b/media/libaom/config/win/x64/config/aom_config.asm @@ -14,7 +14,8 @@ ARCH_MIPS equ 0 ARCH_PPC equ 0 ARCH_X86 equ 0 ARCH_X86_64 equ 1 -CONFIG_2PASS_PARTITION_SEARCH_LVL equ 1 +CONFIG_2PASS_PARTITION_SEARCH_LVL_END equ 3 +CONFIG_2PASS_PARTITION_SEARCH_LVL_START equ 1 CONFIG_ACCOUNTING equ 0 CONFIG_ANALYZER equ 0 CONFIG_AV1_DECODER equ 1 @@ -22,6 +23,7 @@ CONFIG_AV1_ENCODER equ 0 CONFIG_BIG_ENDIAN equ 0 CONFIG_BITSTREAM_DEBUG equ 0 CONFIG_COEFFICIENT_RANGE_CHECKING equ 0 +CONFIG_COLLECT_COMPONENT_TIMING equ 0 CONFIG_COLLECT_PARTITION_STATS equ 0 CONFIG_COLLECT_RD_STATS equ 0 CONFIG_DEBUG equ 0 @@ -30,7 +32,6 @@ CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 equ 1 CONFIG_DIST_8X8 equ 0 CONFIG_ENTROPY_STATS equ 0 CONFIG_FILEOPTIONS equ 1 -CONFIG_FP_MB_STATS equ 0 CONFIG_GCC equ 1 CONFIG_GCOV equ 0 CONFIG_GPROF equ 0 @@ -43,7 +44,6 @@ CONFIG_MAX_DECODE_PROFILE equ 2 CONFIG_MISMATCH_DEBUG equ 0 CONFIG_MULTITHREAD equ 1 CONFIG_NORMAL_TILE_MODE equ 0 -CONFIG_ONE_PASS_SVM equ 0 CONFIG_OS_SUPPORT equ 1 CONFIG_PIC equ 0 CONFIG_RD_DEBUG equ 0 diff --git a/media/libaom/config/win/x64/config/aom_config.h b/media/libaom/config/win/x64/config/aom_config.h index ffff5abe6a..5407b2b76a 100644 --- a/media/libaom/config/win/x64/config/aom_config.h +++ b/media/libaom/config/win/x64/config/aom_config.h @@ -16,7 +16,8 @@ #define ARCH_PPC 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define CONFIG_2PASS_PARTITION_SEARCH_LVL 1 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 +#define CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 #define CONFIG_ACCOUNTING 0 #define CONFIG_ANALYZER 0 #define CONFIG_AV1_DECODER 1 @@ -24,6 +25,7 @@ #define CONFIG_BIG_ENDIAN 0 #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_COEFFICIENT_RANGE_CHECKING 0 +#define CONFIG_COLLECT_COMPONENT_TIMING 0 #define CONFIG_COLLECT_PARTITION_STATS 0 #define CONFIG_COLLECT_RD_STATS 0 #define CONFIG_DEBUG 0 @@ -32,7 +34,6 @@ #define CONFIG_DIST_8X8 0 #define CONFIG_ENTROPY_STATS 0 #define CONFIG_FILEOPTIONS 1 -#define CONFIG_FP_MB_STATS 0 #define CONFIG_GCC 1 #define CONFIG_GCOV 0 #define CONFIG_GPROF 0 @@ -45,7 +46,6 @@ #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_MULTITHREAD 1 #define CONFIG_NORMAL_TILE_MODE 0 -#define CONFIG_ONE_PASS_SVM 0 #define CONFIG_OS_SUPPORT 1 #define CONFIG_PIC 0 #define CONFIG_RD_DEBUG 0 diff --git a/media/libaom/config/win/x64/config/aom_scale_rtcd.h b/media/libaom/config/win/x64/config/aom_scale_rtcd.h index b6e814905b..65c184b83d 100644 --- a/media/libaom/config/win/x64/config/aom_scale_rtcd.h +++ b/media/libaom/config/win/x64/config/aom_scale_rtcd.h @@ -77,6 +77,9 @@ void aom_yv12_partial_copy_v_c(const struct yv12_buffer_config *src_bc, int hsta void aom_yv12_partial_copy_y_c(const struct yv12_buffer_config *src_ybc, int hstart1, int hend1, int vstart1, int vend1, struct yv12_buffer_config *dst_ybc, int hstart2, int vstart2); #define aom_yv12_partial_copy_y aom_yv12_partial_copy_y_c +int aom_yv12_realloc_with_new_border_c(struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes); +#define aom_yv12_realloc_with_new_border aom_yv12_realloc_with_new_border_c + void aom_scale_rtcd(void); #ifdef RTCD_C diff --git a/media/libaom/config/win/x64/config/av1_rtcd.h b/media/libaom/config/win/x64/config/av1_rtcd.h index 80bacb8dd5..c4954fef53 100644 --- a/media/libaom/config/win/x64/config/av1_rtcd.h +++ b/media/libaom/config/win/x64/config/av1_rtcd.h @@ -225,7 +225,6 @@ RTCD_EXTERN void (*av1_highbd_dr_prediction_z3)(uint16_t *dst, ptrdiff_t stride, void av1_highbd_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_highbd_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_highbd_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_highbd_inv_txfm_add_16x4_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); @@ -328,7 +327,6 @@ RTCD_EXTERN void (*av1_inv_txfm2d_add_8x8)(const int32_t *input, uint16_t *outpu void av1_inv_txfm_add_c(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); -void av1_inv_txfm_add_avx2(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param); void av1_round_shift_array_c(int32_t *arr, int size, int bit); @@ -526,7 +524,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_AVX2) av1_highbd_dr_prediction_z3 = av1_highbd_dr_prediction_z3_avx2; av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_sse4_1; - if (flags & HAS_AVX2) av1_highbd_inv_txfm_add = av1_highbd_inv_txfm_add_avx2; av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_c; if (flags & HAS_SSE4_1) av1_highbd_inv_txfm_add_16x4 = av1_highbd_inv_txfm_add_16x4_sse4_1; av1_highbd_inv_txfm_add_4x16 = av1_highbd_inv_txfm_add_4x16_c; @@ -550,7 +547,6 @@ static void setup_rtcd_internal(void) if (flags & HAS_SSE4_1) av1_inv_txfm2d_add_8x8 = av1_inv_txfm2d_add_8x8_sse4_1; av1_inv_txfm_add = av1_inv_txfm_add_c; if (flags & HAS_SSSE3) av1_inv_txfm_add = av1_inv_txfm_add_ssse3; - if (flags & HAS_AVX2) av1_inv_txfm_add = av1_inv_txfm_add_avx2; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_SSE4_1) av1_round_shift_array = av1_round_shift_array_sse4_1; av1_selfguided_restoration = av1_selfguided_restoration_c; diff --git a/third_party/aom/CMakeLists.txt b/third_party/aom/CMakeLists.txt index f409892d27..2c35a0f183 100644 --- a/third_party/aom/CMakeLists.txt +++ b/third_party/aom/CMakeLists.txt @@ -293,8 +293,11 @@ if(CONFIG_AV1_DECODER AND ENABLE_EXAMPLES) if(EMSCRIPTEN) add_preproc_definition(_POSIX_SOURCE) - append_link_flag_to_target("inspect" "-s TOTAL_MEMORY=402653184") + append_link_flag_to_target("inspect" "--emrun") + append_link_flag_to_target("inspect" "-s USE_PTHREADS=0") + append_link_flag_to_target("inspect" "-s WASM=1") append_link_flag_to_target("inspect" "-s MODULARIZE=1") + append_link_flag_to_target("inspect" "-s ALLOW_MEMORY_GROWTH=1") append_link_flag_to_target( "inspect" "-s \'EXTRA_EXPORTED_RUNTIME_METHODS=[\"UTF8ToString\"]\'") append_link_flag_to_target("inspect" diff --git a/third_party/aom/aom/aom_encoder.h b/third_party/aom/aom/aom_encoder.h index 777236f8a2..f8a7cec4eb 100644 --- a/third_party/aom/aom/aom_encoder.h +++ b/third_party/aom/aom/aom_encoder.h @@ -406,8 +406,7 @@ typedef struct aom_codec_enc_cfg { * upscaling after the encode/decode process. Taking control of upscaling and * using restoration filters should allow it to outperform normal resizing. * - * Mode 0 is SUPERRES_NONE, mode 1 is SUPERRES_FIXED, mode 2 is - * SUPERRES_RANDOM and mode 3 is SUPERRES_QTHRESH. + * Valid values are 0 to 4 as defined in enum SUPERRES_MODE. */ unsigned int rc_superres_mode; @@ -862,6 +861,11 @@ aom_codec_err_t aom_codec_enc_config_set(aom_codec_ctx_t *ctx, */ aom_fixed_buf_t *aom_codec_get_global_headers(aom_codec_ctx_t *ctx); +/*!\brief usage parameter analogous to AV1 GOOD QUALITY mode. */ +#define AOM_USAGE_GOOD_QUALITY (0) +/*!\brief usage parameter analogous to AV1 REALTIME mode. */ +#define AOM_USAGE_REALTIME (1) + /*!\brief Encode a frame * * Encodes a video frame at the given "presentation time." The presentation diff --git a/third_party/aom/aom/aomcx.h b/third_party/aom/aom/aomcx.h index fc0f23315f..da7498f6f6 100644 --- a/third_party/aom/aom/aomcx.h +++ b/third_party/aom/aom/aomcx.h @@ -512,16 +512,25 @@ enum aome_enc_control_id { */ AV1E_SET_RENDER_SIZE, - /*!\brief Codec control function to set target level. - * - * 255: off (default); 0: only keep level stats; 10: target for level 1.0; - * 11: target for level 1.1; ... 62: target for level 6.2 + /*!\brief Control to set target sequence level index for a certain operating + * point(OP). + * Possible values are in the form of "ABxy"(pad leading zeros if less than + * 4 digits). + * AB: OP index. + * xy: Target level index for the OP. Can be values 0~23(corresponding to + * level 2.0 ~ 7.3) or 31(maximum level parameter, no level-based + * constraints). + * E.g. "0" means target level index 0 for the 0th OP; + * "111" means target level index 11 for the 1st OP; + * "1021" means target level index 21 for the 10th OP. + * If the target level is not specified for an OP, the maximum level parameter + * of 31 is used as default. */ - AV1E_SET_TARGET_LEVEL, + AV1E_SET_TARGET_SEQ_LEVEL_IDX, - /*!\brief Codec control function to get bitstream level. + /*!\brief Codec control function to get sequence level index. */ - AV1E_GET_LEVEL, + AV1E_GET_SEQ_LEVEL_IDX, /*!\brief Codec control function to set intended superblock size. * @@ -575,8 +584,9 @@ enum aome_enc_control_id { * * 0 = apply trellis quantization * 1 = do not apply trellis quantization + * 2 = disable trellis quantization partially * - * By default, the encoder applies trellis optimization on quantized + * By default, the encoder applies optimization on quantized * coefficients. * */ @@ -718,6 +728,43 @@ enum aome_enc_control_id { */ AV1E_SET_ENABLE_RECT_PARTITIONS, + /*!\brief Codec control function to enable/disable AB partitions. + * + * This will enable or disable usage of AB partitions. The default + * value is 1. + * + */ + AV1E_SET_ENABLE_AB_PARTITIONS, + + /*!\brief Codec control function to enable/disable 1:4 and 4:1 partitions. + * + * This will enable or disable usage of 1:4 and 4:1 partitions. The default + * value is 1. + * + */ + AV1E_SET_ENABLE_1TO4_PARTITIONS, + + /*!\brief Codec control function to set min partition size. + * + * This will set min partition size. The default value is 4 for 4x4. + * valid values are [4, 8, 16, 32, 64, 128] + * min_partition_size is applied to both width and height of the partition. + * i.e, both width and height of a partition can not be smaller than + * the min_partition_size, except the partition at the picture boundary. + * + */ + AV1E_SET_MIN_PARTITION_SIZE, + + /*!\brief Codec control function to set max partition size. + * + * This will set max partition size. The default value is 128 for 128x128. + * valid values are [4, 8, 16, 32, 64, 128] + * max_partition_size is applied to both width and height of the partition. + * i.e, both width and height of a partition can not be larger than + * the max_partition_size. + */ + AV1E_SET_MAX_PARTITION_SIZE, + /*!\brief Codec control function to turn on / off intra edge filter * at sequence level. * @@ -747,6 +794,25 @@ enum aome_enc_control_id { */ AV1E_SET_ENABLE_TX64, + /*!\brief Codec control function to turn on / off flip and identity + * transforms. + * + * This will enable or disable usage of flip and identity transform + * types in any direction. The default value is 1. Including: + * FLIPADST_DCT, DCT_FLIPADST, FLIPADST_FLIPADST, ADST_FLIPADST, + * FLIPADST_ADST, IDTX, V_DCT, H_DCT, V_ADST, H_ADST, V_FLIPADST, + * H_FLIPADST + */ + AV1E_SET_ENABLE_FLIP_IDTX, + + /*!\brief Codec control function to set transform block size search method. + * + * This will set the transform block size search method. + * 0: use Full RD search, 1: use Fast RD search, 2: always use largest + * allowed transform block size based on partition size. + */ + AV1E_SET_TX_SIZE_SEARCH_METHOD, + /*!\brief Codec control function to turn on / off dist-wtd compound mode * at sequence level. * @@ -793,6 +859,15 @@ enum aome_enc_control_id { */ AV1E_SET_ENABLE_MASKED_COMP, + /*!\brief Codec control function to turn on / off one sided compound usage + * for a sequence. + * + * This will enable or disable usage of one sided compound + * modes. The default value is 1. + * + */ + AV1E_SET_ENABLE_ONESIDED_COMP, + /*!\brief Codec control function to turn on / off interintra compound * for a sequence. * @@ -979,16 +1054,44 @@ enum aome_enc_control_id { /*!\brief Control to use dct only for inter modes */ AV1E_SET_INTER_DCT_ONLY, + /*!\brief Control to use default tx type only for intra modes */ + AV1E_SET_INTRA_DEFAULT_TX_ONLY, + /*!\brief Control to use adaptive quantize_b */ AV1E_SET_QUANT_B_ADAPT, /*!\brief Control to select maximum height for the GF group pyramid structure - * (valid values: 1 - 4) */ + * (valid values: 0 - 4) */ AV1E_SET_GF_MAX_PYRAMID_HEIGHT, /*!\brief Control to select maximum reference frames allowed per frame * (valid values: 3 - 7) */ AV1E_SET_MAX_REFERENCE_FRAMES, + + /*!\brief Control to use reduced set of single and compound references. */ + AV1E_SET_REDUCED_REFERENCE_SET, + + /*!\brief Control to set frequency of the cost updates for coefficients + * Possible values are: + * 0: Update at SB level (default) + * 1: Update at SB row level in tile + * 2: Update at tile level + */ + AV1E_SET_COEFF_COST_UPD_FREQ, + + /*!\brief Control to set frequency of the cost updates for mode + * Possible values are: + * 0: Update at SB level (default) + * 1: Update at SB row level in tile + * 2: Update at tile level + */ + AV1E_SET_MODE_COST_UPD_FREQ, + + /*!\brief Control to set bit mask that specifies which tier each of the 32 + * possible operating points conforms to. + * Bit value 0: Main Tier; 1: High Tier. + */ + AV1E_SET_TIER_MASK, }; /*!\brief aom 1-D scaling mode @@ -1095,13 +1198,11 @@ AOM_CTRL_USE_TYPE(AOME_SET_ACTIVEMAP, aom_active_map_t *) AOM_CTRL_USE_TYPE(AOME_SET_SCALEMODE, aom_scaling_mode_t *) #define AOM_CTRL_AOME_SET_SCALEMODE -AOM_CTRL_USE_TYPE(AOME_SET_SPATIAL_LAYER_ID, int) +AOM_CTRL_USE_TYPE(AOME_SET_SPATIAL_LAYER_ID, unsigned int) #define AOM_CTRL_AOME_SET_SPATIAL_LAYER_ID AOM_CTRL_USE_TYPE(AOME_SET_CPUUSED, int) #define AOM_CTRL_AOME_SET_CPUUSED -AOM_CTRL_USE_TYPE(AOME_SET_DEVSF, int) -#define AOM_CTRL_AOME_SET_DEVSF AOM_CTRL_USE_TYPE(AOME_SET_ENABLEAUTOALTREF, unsigned int) #define AOM_CTRL_AOME_SET_ENABLEAUTOALTREF @@ -1122,12 +1223,12 @@ AOM_CTRL_USE_TYPE(AOME_SET_TUNING, int) /* aom_tune_metric */ AOM_CTRL_USE_TYPE(AOME_SET_CQ_LEVEL, unsigned int) #define AOM_CTRL_AOME_SET_CQ_LEVEL -AOM_CTRL_USE_TYPE(AV1E_SET_ROW_MT, int) +AOM_CTRL_USE_TYPE(AV1E_SET_ROW_MT, unsigned int) #define AOM_CTRL_AV1E_SET_ROW_MT -AOM_CTRL_USE_TYPE(AV1E_SET_TILE_COLUMNS, int) +AOM_CTRL_USE_TYPE(AV1E_SET_TILE_COLUMNS, unsigned int) #define AOM_CTRL_AV1E_SET_TILE_COLUMNS -AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, int) +AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, unsigned int) #define AOM_CTRL_AV1E_SET_TILE_ROWS AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TPL_MODEL, unsigned int) @@ -1193,88 +1294,109 @@ AOM_CTRL_USE_TYPE(AV1E_SET_MTU, unsigned int) AOM_CTRL_USE_TYPE(AV1E_SET_TIMING_INFO_TYPE, int) /* aom_timing_info_type_t */ #define AOM_CTRL_AV1E_SET_TIMING_INFO_TYPE -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_RECT_PARTITIONS, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_RECT_PARTITIONS, int) #define AOM_CTRL_AV1E_SET_ENABLE_RECT_PARTITIONS -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_AB_PARTITIONS, int) +#define AOM_CTRL_AV1E_SET_ENABLE_AB_PARTITIONS + +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_1TO4_PARTITIONS, int) +#define AOM_CTRL_AV1E_SET_ENABLE_1TO4_PARTITIONS + +AOM_CTRL_USE_TYPE(AV1E_SET_MIN_PARTITION_SIZE, int) +#define AOM_CTRL_AV1E_SET_MIN_PARTITION_SIZE + +AOM_CTRL_USE_TYPE(AV1E_SET_MAX_PARTITION_SIZE, int) +#define AOM_CTRL_AV1E_SET_MAX_PARTITION_SIZE + +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, int) #define AOM_CTRL_AV1E_SET_ENABLE_INTRA_EDGE_FILTER -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ORDER_HINT, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ORDER_HINT, int) #define AOM_CTRL_AV1E_SET_ENABLE_ORDER_HINT -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TX64, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TX64, int) #define AOM_CTRL_AV1E_SET_ENABLE_TX64 -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIST_WTD_COMP, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_TX_SIZE_SEARCH_METHOD, int) +#define AOM_CTRL_AV1E_SET_TXSIZE_SEARCH_METHOD + +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_FLIP_IDTX, int) +#define AOM_CTRL_AV1E_SET_ENABLE_FLIP_IDTX + +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIST_WTD_COMP, int) #define AOM_CTRL_AV1E_SET_ENABLE_DIST_WTD_COMP -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_REF_FRAME_MVS, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_REF_FRAME_MVS, int) #define AOM_CTRL_AV1E_SET_ENABLE_REF_FRAME_MVS -AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_REF_FRAME_MVS, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_REF_FRAME_MVS, int) #define AOM_CTRL_AV1E_SET_ALLOW_REF_FRAME_MVS -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DUAL_FILTER, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DUAL_FILTER, int) #define AOM_CTRL_AV1E_SET_ENABLE_DUAL_FILTER -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_MASKED_COMP, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_MASKED_COMP, int) #define AOM_CTRL_AV1E_SET_ENABLE_MASKED_COMP -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_COMP, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ONESIDED_COMP, int) +#define AOM_CTRL_AV1E_SET_ENABLE_ONESIDED_COMP + +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_COMP, int) #define AOM_CTRL_AV1E_SET_ENABLE_INTERINTRA_COMP -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTERINTRA, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTERINTRA, int) #define AOM_CTRL_AV1E_SET_ENABLE_SMOOTH_INTERINTRA -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIFF_WTD_COMP, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIFF_WTD_COMP, int) #define AOM_CTRL_AV1E_SET_ENABLE_DIFF_WTD_COMP -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTER_WEDGE, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTER_WEDGE, int) #define AOM_CTRL_AV1E_SET_ENABLE_INTERINTER_WEDGE -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_WEDGE, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_WEDGE, int) #define AOM_CTRL_AV1E_SET_ENABLE_INTERINTRA_WEDGE -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_GLOBAL_MOTION, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_GLOBAL_MOTION, int) #define AOM_CTRL_AV1E_SET_ENABLE_GLOBAL_MOTION -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_WARPED_MOTION, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_WARPED_MOTION, int) #define AOM_CTRL_AV1E_SET_ENABLE_WARPED_MOTION -AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_WARPED_MOTION, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_WARPED_MOTION, int) #define AOM_CTRL_AV1E_SET_ALLOW_WARPED_MOTION -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_FILTER_INTRA, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_FILTER_INTRA, int) #define AOM_CTRL_AV1E_SET_ENABLE_FILTER_INTRA -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTRA, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTRA, int) #define AOM_CTRL_AV1E_SET_ENABLE_SMOOTH_INTRA -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PAETH_INTRA, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PAETH_INTRA, int) #define AOM_CTRL_AV1E_SET_ENABLE_PAETH_INTRA -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_CFL_INTRA, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_CFL_INTRA, int) #define AOM_CTRL_AV1E_SET_ENABLE_CFL_INTRA -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SUPERRES, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SUPERRES, int) #define AOM_CTRL_AV1E_SET_ENABLE_SUPERRES -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PALETTE, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PALETTE, int) #define AOM_CTRL_AV1E_SET_ENABLE_PALETTE -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRABC, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRABC, int) #define AOM_CTRL_AV1E_SET_ENABLE_INTRABC -AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ANGLE_DELTA, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ANGLE_DELTA, int) #define AOM_CTRL_AV1E_SET_ENABLE_ANGLE_DELTA AOM_CTRL_USE_TYPE(AV1E_SET_FRAME_PARALLEL_DECODING, unsigned int) #define AOM_CTRL_AV1E_SET_FRAME_PARALLEL_DECODING -AOM_CTRL_USE_TYPE(AV1E_SET_ERROR_RESILIENT_MODE, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_ERROR_RESILIENT_MODE, int) #define AOM_CTRL_AV1E_SET_ERROR_RESILIENT_MODE -AOM_CTRL_USE_TYPE(AV1E_SET_S_FRAME_MODE, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_S_FRAME_MODE, int) #define AOM_CTRL_AV1E_SET_S_FRAME_MODE AOM_CTRL_USE_TYPE(AV1E_SET_AQ_MODE, unsigned int) @@ -1322,14 +1444,8 @@ AOM_CTRL_USE_TYPE(AV1E_SET_RENDER_SIZE, int *) AOM_CTRL_USE_TYPE(AV1E_SET_SUPERBLOCK_SIZE, unsigned int) #define AOM_CTRL_AV1E_SET_SUPERBLOCK_SIZE -AOM_CTRL_USE_TYPE(AV1E_SET_TARGET_LEVEL, unsigned int) -#define AOM_CTRL_AV1E_SET_TARGET_LEVEL - -AOM_CTRL_USE_TYPE(AV1E_GET_LEVEL, int *) -#define AOM_CTRL_AV1E_GET_LEVEL - -AOM_CTRL_USE_TYPE(AV1E_SET_ANS_WINDOW_SIZE_LOG2, unsigned int) -#define AOM_CTRL_AV1E_SET_ANS_WINDOW_SIZE_LOG2 +AOM_CTRL_USE_TYPE(AV1E_GET_SEQ_LEVEL_IDX, int *) +#define AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX AOM_CTRL_USE_TYPE(AV1E_SET_SINGLE_TILE_DECODING, unsigned int) #define AOM_CTRL_AV1E_SET_SINGLE_TILE_DECODING @@ -1337,13 +1453,13 @@ AOM_CTRL_USE_TYPE(AV1E_SET_SINGLE_TILE_DECODING, unsigned int) AOM_CTRL_USE_TYPE(AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, unsigned int) #define AOM_CTRL_AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST -AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TEST_VECTOR, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TEST_VECTOR, int) #define AOM_CTRL_AV1E_SET_FILM_GRAIN_TEST_VECTOR AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TABLE, const char *) #define AOM_CTRL_AV1E_SET_FILM_GRAIN_TABLE -AOM_CTRL_USE_TYPE(AV1E_SET_CDF_UPDATE_MODE, int) +AOM_CTRL_USE_TYPE(AV1E_SET_CDF_UPDATE_MODE, unsigned int) #define AOM_CTRL_AV1E_SET_CDF_UPDATE_MODE #ifdef CONFIG_DENOISE @@ -1360,24 +1476,42 @@ AOM_CTRL_USE_TYPE(AV1E_SET_CHROMA_SUBSAMPLING_X, unsigned int) AOM_CTRL_USE_TYPE(AV1E_SET_CHROMA_SUBSAMPLING_Y, unsigned int) #define AOM_CTRL_AV1E_SET_CHROMA_SUBSAMPLING_Y -AOM_CTRL_USE_TYPE(AV1E_SET_REDUCED_TX_TYPE_SET, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_REDUCED_TX_TYPE_SET, int) #define AOM_CTRL_AV1E_SET_REDUCED_TX_TYPE_SET -AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DCT_ONLY, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DCT_ONLY, int) #define AOM_CTRL_AV1E_SET_INTRA_DCT_ONLY -AOM_CTRL_USE_TYPE(AV1E_SET_INTER_DCT_ONLY, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_INTER_DCT_ONLY, int) #define AOM_CTRL_AV1E_SET_INTER_DCT_ONLY -AOM_CTRL_USE_TYPE(AV1E_SET_QUANT_B_ADAPT, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DEFAULT_TX_ONLY, int) +#define AOM_CTRL_AV1E_SET_INTRA_DEFAULT_TX_ONLY + +AOM_CTRL_USE_TYPE(AV1E_SET_QUANT_B_ADAPT, int) #define AOM_CTRL_AV1E_SET_QUANT_B_ADAPT AOM_CTRL_USE_TYPE(AV1E_SET_GF_MAX_PYRAMID_HEIGHT, unsigned int) #define AOM_CTRL_AV1E_SET_GF_MAX_PYRAMID_HEIGHT -AOM_CTRL_USE_TYPE(AV1E_SET_MAX_REFERENCE_FRAMES, unsigned int) +AOM_CTRL_USE_TYPE(AV1E_SET_MAX_REFERENCE_FRAMES, int) #define AOM_CTRL_AV1E_SET_MAX_REFERENCE_FRAMES +AOM_CTRL_USE_TYPE(AV1E_SET_REDUCED_REFERENCE_SET, int) +#define AOM_CTRL_AV1E_SET_REDUCED_REFERENCE_SET + +AOM_CTRL_USE_TYPE(AV1E_SET_COEFF_COST_UPD_FREQ, unsigned int) +#define AOM_CTRL_AV1E_SET_COEFF_COST_UPD_FREQ + +AOM_CTRL_USE_TYPE(AV1E_SET_MODE_COST_UPD_FREQ, unsigned int) +#define AOM_CTRL_AV1E_SET_MODE_COST_UPD_FREQ + +AOM_CTRL_USE_TYPE(AV1E_SET_TARGET_SEQ_LEVEL_IDX, int) +#define AOM_CTRL_AV1E_SET_TARGET_SEQ_LEVEL_IDX + +AOM_CTRL_USE_TYPE(AV1E_SET_TIER_MASK, unsigned int) +#define AOM_CTRL_AV1E_SET_TIER_MASK + /*!\endcond */ /*! @} - end defgroup aom_encoder */ #ifdef __cplusplus diff --git a/third_party/aom/aom_dsp/aom_dsp.cmake b/third_party/aom/aom_dsp/aom_dsp.cmake index c6a6e3df59..abf6a60562 100644 --- a/third_party/aom/aom_dsp/aom_dsp.cmake +++ b/third_party/aom/aom_dsp/aom_dsp.cmake @@ -194,6 +194,7 @@ if(CONFIG_AV1_ENCODER) "${AOM_ROOT}/aom_dsp/x86/highbd_subtract_sse2.c" "${AOM_ROOT}/aom_dsp/x86/highbd_variance_sse2.c" "${AOM_ROOT}/aom_dsp/x86/quantize_sse2.c" + "${AOM_ROOT}/aom_dsp/x86/adaptive_quantize_sse2.c" "${AOM_ROOT}/aom_dsp/x86/quantize_x86.h" "${AOM_ROOT}/aom_dsp/x86/sum_squares_sse2.c" "${AOM_ROOT}/aom_dsp/x86/variance_sse2.c") @@ -362,6 +363,8 @@ function(setup_aom_dsp_targets) endif() endif() + target_sources(aom PRIVATE $) + # Pass the new lib targets up to the parent scope instance of # $AOM_LIB_TARGETS. set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE) diff --git a/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl b/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl index ff0f65333c..f56a1170c2 100755 --- a/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl +++ b/third_party/aom/aom_dsp/aom_dsp_rtcd_defs.pl @@ -518,9 +518,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/void aom_quantize_b/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; specialize qw/aom_quantize_b sse2/, "$ssse3_x86_64", "$avx_x86_64"; + add_proto qw/void aom_quantize_b_adaptive/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; + specialize qw/aom_quantize_b_adaptive sse2/; + add_proto qw/void aom_quantize_b_32x32/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; specialize qw/aom_quantize_b_32x32/, "$ssse3_x86_64", "$avx_x86_64"; + add_proto qw/void aom_quantize_b_32x32_adaptive/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; + specialize qw/aom_quantize_b_32x32_adaptive sse2/; + add_proto qw/void aom_quantize_b_64x64/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; specialize qw/aom_quantize_b_64x64 ssse3/; } # CONFIG_AV1_ENCODER @@ -533,7 +539,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_highbd_quantize_b_32x32 sse2/; add_proto qw/void aom_highbd_quantize_b_64x64/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan"; - + specialize qw/aom_highbd_quantize_b_64x64 sse2/; } # CONFIG_AV1_ENCODER # @@ -835,6 +841,30 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_highbd_sad16x64x4d sse2/; specialize qw/aom_highbd_sad64x16x4d sse2/; + # + # Avg + # + add_proto qw/unsigned int aom_avg_8x8/, "const uint8_t *, int p"; + specialize qw/aom_avg_8x8 sse2/; + + add_proto qw/unsigned int aom_avg_4x4/, "const uint8_t *, int p"; + specialize qw/aom_avg_4x4 sse2/; + + add_proto qw/void aom_minmax_8x8/, "const uint8_t *s, int p, const uint8_t *d, int dp, int *min, int *max"; + specialize qw/aom_minmax_8x8 sse2/; + + add_proto qw/void aom_int_pro_row/, "int16_t *hbuf, const uint8_t *ref, const int ref_stride, const int height"; + # TODO(kyslov@) bring back SSE2 by extending it to 128 block size + #specialize qw/aom_int_pro_row sse2/; + + add_proto qw/int16_t aom_int_pro_col/, "const uint8_t *ref, const int width"; + # TODO(kyslov@) bring back SSE2 by extending it to 128 block size + #specialize qw/aom_int_pro_col sse2/; + + add_proto qw/int aom_vector_var/, "const int16_t *ref, const int16_t *src, const int bwl"; + # TODO(kyslov@) bring back SSE2 by extending it to 128 block size + #specialize qw/aom_vector_var sse2/; + # # hamadard transform and satd for implmenting temporal dependency model # @@ -1358,6 +1388,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { # # Subpixel Variance # + add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance128x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_12_sub_pixel_variance128x128 sse2/; + + add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance128x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_12_sub_pixel_variance128x64 sse2/; + + add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance64x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_12_sub_pixel_variance64x128 sse2/; + add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; specialize qw/aom_highbd_12_sub_pixel_variance64x64 sse2/; @@ -1394,6 +1433,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance4x8/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance4x4/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance128x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_10_sub_pixel_variance128x128 sse2/; + + add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance128x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_10_sub_pixel_variance128x64 sse2/; + + add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance64x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_10_sub_pixel_variance64x128 sse2/; + add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; specialize qw/aom_highbd_10_sub_pixel_variance64x64 sse2/; @@ -1430,6 +1478,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance4x8/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance4x4/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance128x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_8_sub_pixel_variance128x128 sse2/; + + add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance128x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_8_sub_pixel_variance128x64 sse2/; + + add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance64x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; + specialize qw/aom_highbd_8_sub_pixel_variance64x128 sse2/; + add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse"; specialize qw/aom_highbd_8_sub_pixel_variance64x64 sse2/; diff --git a/third_party/aom/aom_dsp/avg.c b/third_party/aom/aom_dsp/avg.c index 4d78c9c569..43d27600ea 100644 --- a/third_party/aom/aom_dsp/avg.c +++ b/third_party/aom/aom_dsp/avg.c @@ -14,6 +14,40 @@ #include "config/aom_dsp_rtcd.h" #include "aom_ports/mem.h" +void aom_minmax_8x8_c(const uint8_t *s, int p, const uint8_t *d, int dp, + int *min, int *max) { + int i, j; + *min = 255; + *max = 0; + for (i = 0; i < 8; ++i, s += p, d += dp) { + for (j = 0; j < 8; ++j) { + int diff = abs(s[j] - d[j]); + *min = diff < *min ? diff : *min; + *max = diff > *max ? diff : *max; + } + } +} + +unsigned int aom_avg_4x4_c(const uint8_t *s, int p) { + int i, j; + int sum = 0; + for (i = 0; i < 4; ++i, s += p) + for (j = 0; j < 4; sum += s[j], ++j) { + } + + return (sum + 8) >> 4; +} + +unsigned int aom_avg_8x8_c(const uint8_t *s, int p) { + int i, j; + int sum = 0; + for (i = 0; i < 8; ++i, s += p) + for (j = 0; j < 8; sum += s[j], ++j) { + } + + return (sum + 32) >> 6; +} + // src_diff: first pass, 9 bit, dynamic range [-255, 255] // second pass, 12 bit, dynamic range [-2040, 2040] static void hadamard_col8(const int16_t *src_diff, ptrdiff_t src_stride, @@ -146,3 +180,48 @@ int aom_satd_c(const tran_low_t *coeff, int length) { // satd: 26 bits, dynamic range [-32640 * 1024, 32640 * 1024] return satd; } + +// Integer projection onto row vectors. +// height: value range {16, 32, 64, 128}. +void aom_int_pro_row_c(int16_t hbuf[16], const uint8_t *ref, + const int ref_stride, const int height) { + int idx; + const int norm_factor = height >> 1; + for (idx = 0; idx < 16; ++idx) { + int i; + hbuf[idx] = 0; + // hbuf[idx]: 14 bit, dynamic range [0, 32640]. + for (i = 0; i < height; ++i) hbuf[idx] += ref[i * ref_stride]; + // hbuf[idx]: 9 bit, dynamic range [0, 1020]. + hbuf[idx] /= norm_factor; + ++ref; + } +} + +// width: value range {16, 32, 64, 128}. +int16_t aom_int_pro_col_c(const uint8_t *ref, const int width) { + int idx; + int16_t sum = 0; + // sum: 14 bit, dynamic range [0, 32640] + for (idx = 0; idx < width; ++idx) sum += ref[idx]; + return sum; +} + +// ref: [0 - 510] +// src: [0 - 510] +// bwl: {2, 3, 4, 5} +int aom_vector_var_c(const int16_t *ref, const int16_t *src, const int bwl) { + int i; + int width = 4 << bwl; + int sse = 0, mean = 0, var; + + for (i = 0; i < width; ++i) { + int diff = ref[i] - src[i]; // diff: dynamic range [-510, 510], 10 bits. + mean += diff; // mean: dynamic range 16 bits. + sse += diff * diff; // sse: dynamic range 26 bits. + } + + // (mean * mean): dynamic range 31 bits. + var = sse - ((mean * mean) >> (bwl + 2)); + return var; +} diff --git a/third_party/aom/aom_dsp/bitreader_buffer.c b/third_party/aom/aom_dsp/bitreader_buffer.c index 984b217738..d79feea6a3 100644 --- a/third_party/aom/aom_dsp/bitreader_buffer.c +++ b/third_party/aom/aom_dsp/bitreader_buffer.c @@ -60,9 +60,9 @@ int aom_rb_read_inv_signed_literal(struct aom_read_bit_buffer *rb, int bits) { uint32_t aom_rb_read_uvlc(struct aom_read_bit_buffer *rb) { int leading_zeros = 0; - while (!aom_rb_read_bit(rb)) ++leading_zeros; + while (leading_zeros < 32 && !aom_rb_read_bit(rb)) ++leading_zeros; // Maximum 32 bits. - if (leading_zeros >= 32) return UINT32_MAX; + if (leading_zeros == 32) return UINT32_MAX; const uint32_t base = (1u << leading_zeros) - 1; const uint32_t value = aom_rb_read_literal(rb, leading_zeros); return base + value; diff --git a/third_party/aom/aom_dsp/grain_synthesis.c b/third_party/aom/aom_dsp/grain_synthesis.c index b96e1c3190..4b94dbc1ac 100644 --- a/third_party/aom/aom_dsp/grain_synthesis.c +++ b/third_party/aom/aom_dsp/grain_synthesis.c @@ -232,7 +232,6 @@ static int scaling_lut_y[256]; static int scaling_lut_cb[256]; static int scaling_lut_cr[256]; -static int grain_center; static int grain_min; static int grain_max; @@ -1077,7 +1076,7 @@ int av1_add_film_grain_run(const aom_film_grain_t *params, uint8_t *luma, int overlap = params->overlap_flag; int bit_depth = params->bit_depth; - grain_center = 128 << (bit_depth - 8); + const int grain_center = 128 << (bit_depth - 8); grain_min = 0 - grain_center; grain_max = (256 << (bit_depth - 8)) - 1 - grain_center; diff --git a/third_party/aom/aom_dsp/quantize.c b/third_party/aom/aom_dsp/quantize.c index 4acbf20939..ced34b4b06 100644 --- a/third_party/aom/aom_dsp/quantize.c +++ b/third_party/aom/aom_dsp/quantize.c @@ -11,6 +11,7 @@ #include "aom_dsp/quantize.h" #include "aom_mem/aom_mem.h" +#include "av1/encoder/av1_quantize.h" void quantize_b_adaptive_helper_c( const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, @@ -28,15 +29,18 @@ void quantize_b_adaptive_helper_c( memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr)); memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr)); + int prescan_add[2]; + for (i = 0; i < 2; ++i) + prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7); + // Pre-scan pass for (i = (int)n_coeffs - 1; i >= 0; i--) { const int rc = scan[i]; const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS); const int coeff = coeff_ptr[rc] * wt; - - int prescan_add = ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * 325, 7); - if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add) && - coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add)) + const int prescan_add_val = prescan_add[rc != 0]; + if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) && + coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val)) non_zero_count--; else break; @@ -44,6 +48,9 @@ void quantize_b_adaptive_helper_c( // Quantization pass: All coefficients with index >= zero_flag are // skippable. Note: zero_flag can be zero. +#if SKIP_EOB_FACTOR_ADJUST + int first = -1; +#endif // SKIP_EOB_FACTOR_ADJUST for (i = 0; i < non_zero_count; i++) { const int rc = scan[i]; const int coeff = coeff_ptr[rc]; @@ -68,9 +75,32 @@ void quantize_b_adaptive_helper_c( const tran_low_t abs_dqcoeff = (tmp32 * dequant) >> log_scale; dqcoeff_ptr[rc] = (tran_low_t)((abs_dqcoeff ^ coeff_sign) - coeff_sign); - if (tmp32) eob = i; + if (tmp32) { + eob = i; +#if SKIP_EOB_FACTOR_ADJUST + if (first == -1) first = i; +#endif // SKIP_EOB_FACTOR_ADJUST + } } } +#if SKIP_EOB_FACTOR_ADJUST + if (eob >= 0 && first == eob) { + const int rc = scan[eob]; + if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { + const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS); + const int coeff = coeff_ptr[rc] * wt; + const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; + const int prescan_add_val = + ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7); + if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) && + coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val)) { + qcoeff_ptr[rc] = 0; + dqcoeff_ptr[rc] = 0; + eob = -1; + } + } + } +#endif // SKIP_EOB_FACTOR_ADJUST *eob_ptr = eob + 1; } @@ -155,6 +185,10 @@ void highbd_quantize_b_adaptive_helper_c( memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr)); memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr)); + int prescan_add[2]; + for (i = 0; i < 2; ++i) + prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7); + // Pre-scan pass for (i = 0; i < n_coeffs; i++) { const int rc = scan[i]; @@ -163,14 +197,17 @@ void highbd_quantize_b_adaptive_helper_c( // If the coefficient is out of the base ZBIN range, keep it for // quantization. - int prescan_add = ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * 325, 7); - if (coeff >= (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add) && - coeff <= (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add)) + const int prescan_add_val = prescan_add[rc != 0]; + if (coeff >= (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) && + coeff <= (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val)) idx_arr[idx++] = i; } // Quantization pass: only process the coefficients selected in // pre-scan pass. Note: idx can be zero. +#if SKIP_EOB_FACTOR_ADJUST + int first = -1; +#endif // SKIP_EOB_FACTOR_ADJUST for (i = 0; i < idx; i++) { const int rc = scan[idx_arr[i]]; const int coeff = coeff_ptr[rc]; @@ -189,8 +226,31 @@ void highbd_quantize_b_adaptive_helper_c( (dequant_ptr[rc != 0] * iwt + (1 << (AOM_QM_BITS - 1))) >> AOM_QM_BITS; const tran_low_t abs_dqcoeff = (abs_qcoeff * dequant) >> log_scale; dqcoeff_ptr[rc] = (tran_low_t)((abs_dqcoeff ^ coeff_sign) - coeff_sign); - if (abs_qcoeff) eob = idx_arr[i]; + if (abs_qcoeff) { + eob = idx_arr[i]; +#if SKIP_EOB_FACTOR_ADJUST + if (first == -1) first = eob; +#endif // SKIP_EOB_FACTOR_ADJUST + } } +#if SKIP_EOB_FACTOR_ADJUST + if (eob >= 0 && first == eob) { + const int rc = scan[eob]; + if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { + const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS); + const int coeff = coeff_ptr[rc] * wt; + const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; + const int prescan_add_val = + ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7); + if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) && + coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val)) { + qcoeff_ptr[rc] = 0; + dqcoeff_ptr[rc] = 0; + eob = -1; + } + } + } +#endif // SKIP_EOB_FACTOR_ADJUST *eob_ptr = eob + 1; } diff --git a/third_party/aom/aom_dsp/x86/adaptive_quantize_sse2.c b/third_party/aom/aom_dsp/x86/adaptive_quantize_sse2.c new file mode 100644 index 0000000000..3822c27aaf --- /dev/null +++ b/third_party/aom/aom_dsp/x86/adaptive_quantize_sse2.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2019, 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 +#include +#include "config/aom_dsp_rtcd.h" +#include "aom/aom_integer.h" +#include "av1/encoder/av1_quantize.h" +#include "aom_dsp/x86/quantize_x86.h" + +void aom_quantize_b_adaptive_sse2( + const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, + const int16_t *round_ptr, const int16_t *quant_ptr, + const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, + tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, + const int16_t *scan, const int16_t *iscan) { + const __m128i zero = _mm_setzero_si128(); + int index = 16; + int non_zero_count = (int)n_coeffs; + __m128i zbin, round, quant, dequant, shift; + __m128i coeff0, coeff1, coeff0_sign, coeff1_sign; + __m128i qcoeff0, qcoeff1; + __m128i cmp_mask0, cmp_mask1; + __m128i eob = zero, eob0, prescan0, prescan1, all_zero; + const int zbins[2] = { ROUND_POWER_OF_TWO(zbin_ptr[0], 0), + ROUND_POWER_OF_TWO(zbin_ptr[1], 0) }; + + int prescan_add[2]; + for (int i = 0; i < 2; ++i) + prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7); + + // max buffer is of size 256 as this functions calls with + // maximum n_coeffs as 256 + int16_t prescan[256]; + memset(prescan, -1, n_coeffs * sizeof(int16_t)); + + // TODO(Aniket): Experiment the following loop with intrinsic + for (int i = (int)n_coeffs - 1; i >= 0; i--) { + const int rc = scan[i]; + const qm_val_t wt = 1 << AOM_QM_BITS; + const int coeff = coeff_ptr[rc] * wt; + const int coeff_sign = (coeff >> 31); + const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + const int prescan_add_val = prescan_add[rc != 0]; + if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) { + prescan[rc] = 0; + non_zero_count--; + } else { + break; + } + } +#if SKIP_EOB_FACTOR_ADJUST + int first = -1; +#endif + // Setup global values. + load_b_values(zbin_ptr, &zbin, round_ptr, &round, quant_ptr, &quant, + dequant_ptr, &dequant, quant_shift_ptr, &shift); + + // Do DC and first 15 AC. + coeff0 = load_coefficients(coeff_ptr); + coeff1 = load_coefficients(coeff_ptr + 8); + + // Poor man's abs(). + coeff0_sign = _mm_srai_epi16(coeff0, 15); + coeff1_sign = _mm_srai_epi16(coeff1, 15); + qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign); + + prescan0 = _mm_loadu_si128((const __m128i *)prescan); + prescan1 = _mm_loadu_si128((const __m128i *)(prescan + 8)); + + cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin)); + zbin = _mm_unpackhi_epi64(zbin, zbin); // Switch DC to AC + cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin)); + + all_zero = _mm_or_si128(cmp_mask0, cmp_mask1); + if (_mm_movemask_epi8(all_zero) == 0) { + _mm_store_si128((__m128i *)(qcoeff_ptr), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + 4), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + 8), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + 12), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + 4), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + 8), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + 12), zero); + round = _mm_unpackhi_epi64(round, round); + quant = _mm_unpackhi_epi64(quant, quant); + shift = _mm_unpackhi_epi64(shift, shift); + dequant = _mm_unpackhi_epi64(dequant, dequant); + } else { + calculate_qcoeff(&qcoeff0, round, quant, shift); + + round = _mm_unpackhi_epi64(round, round); + quant = _mm_unpackhi_epi64(quant, quant); + shift = _mm_unpackhi_epi64(shift, shift); + + calculate_qcoeff(&qcoeff1, round, quant, shift); + + // Reinsert signs + qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign); + + // Mask out zbin threshold coeffs + qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0); + qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1); + + store_coefficients(qcoeff0, qcoeff_ptr); + store_coefficients(qcoeff1, qcoeff_ptr + 8); + + coeff0 = calculate_dqcoeff(qcoeff0, dequant); + dequant = _mm_unpackhi_epi64(dequant, dequant); + coeff1 = calculate_dqcoeff(qcoeff1, dequant); + + store_coefficients(coeff0, dqcoeff_ptr); + store_coefficients(coeff1, dqcoeff_ptr + 8); + + eob = scan_for_eob(&coeff0, &coeff1, cmp_mask0, cmp_mask1, iscan, 0, zero); + } + + // AC only loop. + // TODO(Aniket): Reduce the processing of coeff quatization + // based on eob logic + while (index < n_coeffs) { + coeff0 = load_coefficients(coeff_ptr + index); + coeff1 = load_coefficients(coeff_ptr + index + 8); + + coeff0_sign = _mm_srai_epi16(coeff0, 15); + coeff1_sign = _mm_srai_epi16(coeff1, 15); + qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign); + + prescan0 = _mm_loadu_si128((const __m128i *)(prescan + index)); + prescan1 = _mm_loadu_si128((const __m128i *)(prescan + index + 8)); + + cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin)); + cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin)); + + all_zero = _mm_or_si128(cmp_mask0, cmp_mask1); + if (_mm_movemask_epi8(all_zero) == 0) { + _mm_store_si128((__m128i *)(qcoeff_ptr + index), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + index + 4), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + index + 8), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + index + 12), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index + 4), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index + 8), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index + 12), zero); + index += 16; + continue; + } + calculate_qcoeff(&qcoeff0, round, quant, shift); + calculate_qcoeff(&qcoeff1, round, quant, shift); + + qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign); + + qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0); + qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1); + + store_coefficients(qcoeff0, qcoeff_ptr + index); + store_coefficients(qcoeff1, qcoeff_ptr + index + 8); + + coeff0 = calculate_dqcoeff(qcoeff0, dequant); + coeff1 = calculate_dqcoeff(qcoeff1, dequant); + + store_coefficients(coeff0, dqcoeff_ptr + index); + store_coefficients(coeff1, dqcoeff_ptr + index + 8); + + eob0 = scan_for_eob(&coeff0, &coeff1, cmp_mask0, cmp_mask1, iscan, index, + zero); + eob = _mm_max_epi16(eob, eob0); + index += 16; + } + + *eob_ptr = accumulate_eob(eob); + +#if SKIP_EOB_FACTOR_ADJUST + // TODO(Aniket): Experiment the following loop with intrinsic by combining + // with the quantization loop above + for (int i = 0; i < non_zero_count; i++) { + const int rc = scan[i]; + const int qcoeff = qcoeff_ptr[rc]; + if (qcoeff) { + first = i; + break; + } + } + if ((*eob_ptr - 1) >= 0 && first == (*eob_ptr - 1)) { + const int rc = scan[(*eob_ptr - 1)]; + if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { + const qm_val_t wt = (1 << AOM_QM_BITS); + const int coeff = coeff_ptr[rc] * wt; + const int coeff_sign = (coeff >> 31); + const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; + const int prescan_add_val = + ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7); + if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) { + qcoeff_ptr[rc] = 0; + dqcoeff_ptr[rc] = 0; + *eob_ptr = 0; + } + } + } +#endif +} + +void aom_quantize_b_32x32_adaptive_sse2( + const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, + const int16_t *round_ptr, const int16_t *quant_ptr, + const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, + tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, + const int16_t *scan, const int16_t *iscan) { + int index = 16; + int non_zero_count = (int)n_coeffs; + const int log_scale = 1; + const __m128i zero = _mm_setzero_si128(); + const __m128i one = _mm_set1_epi16(1); + const __m128i log_scale_vec = _mm_set1_epi16(log_scale); + __m128i zbin, round, quant, dequant, shift; + __m128i coeff0, coeff1, coeff0_sign, coeff1_sign; + __m128i qcoeff0, qcoeff1; + __m128i cmp_mask0, cmp_mask1; + __m128i eob = zero, eob0, prescan0, prescan1, all_zero; + const int zbins[2] = { ROUND_POWER_OF_TWO(zbin_ptr[0], log_scale), + ROUND_POWER_OF_TWO(zbin_ptr[1], log_scale) }; + + int prescan_add[2]; + for (int i = 0; i < 2; ++i) + prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7); + + // max buffer is of size 1024 as this functions calls with + // maximum n_coeffs as 1024 + int16_t prescan[1024]; + memset(prescan, -1, n_coeffs * sizeof(int16_t)); + + // TODO(Aniket): Experiment the following loop with intrinsic + for (int i = (int)n_coeffs - 1; i >= 0; i--) { + const int rc = scan[i]; + const qm_val_t wt = 1 << AOM_QM_BITS; + const int coeff = coeff_ptr[rc] * wt; + const int coeff_sign = (coeff >> 31); + const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + const int prescan_add_val = prescan_add[rc != 0]; + if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) { + prescan[rc] = 0; + non_zero_count--; + } else { + break; + } + } +#if SKIP_EOB_FACTOR_ADJUST + int first = -1; +#endif + // Setup global values. + zbin = _mm_load_si128((const __m128i *)zbin_ptr); + round = _mm_load_si128((const __m128i *)round_ptr); + quant = _mm_load_si128((const __m128i *)quant_ptr); + dequant = _mm_load_si128((const __m128i *)dequant_ptr); + shift = _mm_load_si128((const __m128i *)quant_shift_ptr); + + // Shift with rounding. + zbin = _mm_add_epi16(zbin, log_scale_vec); + round = _mm_add_epi16(round, log_scale_vec); + zbin = _mm_srli_epi16(zbin, log_scale); + round = _mm_srli_epi16(round, log_scale); + zbin = _mm_sub_epi16(zbin, one); + // Do DC and first 15 AC. + coeff0 = load_coefficients(coeff_ptr); + coeff1 = load_coefficients(coeff_ptr + 8); + + coeff0_sign = _mm_srai_epi16(coeff0, 15); + coeff1_sign = _mm_srai_epi16(coeff1, 15); + qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign); + + prescan0 = _mm_loadu_si128((const __m128i *)prescan); + prescan1 = _mm_loadu_si128((const __m128i *)(prescan + 8)); + + cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin)); + zbin = _mm_unpackhi_epi64(zbin, zbin); // Switch DC to AC + cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin)); + + all_zero = _mm_or_si128(cmp_mask0, cmp_mask1); + if (_mm_movemask_epi8(all_zero) == 0) { + _mm_store_si128((__m128i *)(qcoeff_ptr), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + 4), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + 8), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + 12), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + 4), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + 8), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + 12), zero); + round = _mm_unpackhi_epi64(round, round); + quant = _mm_unpackhi_epi64(quant, quant); + shift = _mm_unpackhi_epi64(shift, shift); + dequant = _mm_unpackhi_epi64(dequant, dequant); + } else { + calculate_qcoeff_log_scale(&qcoeff0, round, quant, &shift, &log_scale); + + round = _mm_unpackhi_epi64(round, round); + quant = _mm_unpackhi_epi64(quant, quant); + shift = _mm_unpackhi_epi64(shift, shift); + + calculate_qcoeff_log_scale(&qcoeff1, round, quant, &shift, &log_scale); + + // Reinsert signs + qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign); + + // Mask out zbin threshold coeffs + qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0); + qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1); + + store_coefficients(qcoeff0, qcoeff_ptr); + store_coefficients(qcoeff1, qcoeff_ptr + 8); + + calculate_dqcoeff_and_store_log_scale(qcoeff0, dequant, zero, dqcoeff_ptr, + &log_scale); + dequant = _mm_unpackhi_epi64(dequant, dequant); + calculate_dqcoeff_and_store_log_scale(qcoeff1, dequant, zero, + dqcoeff_ptr + 8, &log_scale); + + eob = + scan_for_eob(&qcoeff0, &qcoeff1, cmp_mask0, cmp_mask1, iscan, 0, zero); + } + + // AC only loop. + // TODO(Aniket): Reduce the processing of coeff quatization + // based on eob logic + while (index < n_coeffs) { + coeff0 = load_coefficients(coeff_ptr + index); + coeff1 = load_coefficients(coeff_ptr + index + 8); + + coeff0_sign = _mm_srai_epi16(coeff0, 15); + coeff1_sign = _mm_srai_epi16(coeff1, 15); + qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign); + + prescan0 = _mm_loadu_si128((const __m128i *)(prescan + index)); + prescan1 = _mm_loadu_si128((const __m128i *)(prescan + index + 8)); + + cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin)); + cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin)); + + all_zero = _mm_or_si128(cmp_mask0, cmp_mask1); + if (_mm_movemask_epi8(all_zero) == 0) { + _mm_store_si128((__m128i *)(qcoeff_ptr + index), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + index + 4), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + index + 8), zero); + _mm_store_si128((__m128i *)(qcoeff_ptr + index + 12), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index + 4), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index + 8), zero); + _mm_store_si128((__m128i *)(dqcoeff_ptr + index + 12), zero); + index += 16; + continue; + } + calculate_qcoeff_log_scale(&qcoeff0, round, quant, &shift, &log_scale); + calculate_qcoeff_log_scale(&qcoeff1, round, quant, &shift, &log_scale); + + qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign); + qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign); + + qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0); + qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1); + + store_coefficients(qcoeff0, qcoeff_ptr + index); + store_coefficients(qcoeff1, qcoeff_ptr + index + 8); + + calculate_dqcoeff_and_store_log_scale(qcoeff0, dequant, zero, + dqcoeff_ptr + index, &log_scale); + calculate_dqcoeff_and_store_log_scale(qcoeff1, dequant, zero, + dqcoeff_ptr + index + 8, &log_scale); + + eob0 = scan_for_eob(&qcoeff0, &qcoeff1, cmp_mask0, cmp_mask1, iscan, index, + zero); + eob = _mm_max_epi16(eob, eob0); + index += 16; + } + + *eob_ptr = accumulate_eob(eob); + +#if SKIP_EOB_FACTOR_ADJUST + // TODO(Aniket): Experiment the following loop with intrinsic by combining + // with the quantization loop above + for (int i = 0; i < non_zero_count; i++) { + const int rc = scan[i]; + const int qcoeff = qcoeff_ptr[rc]; + if (qcoeff) { + first = i; + break; + } + } + if ((*eob_ptr - 1) >= 0 && first == (*eob_ptr - 1)) { + const int rc = scan[(*eob_ptr - 1)]; + if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { + const qm_val_t wt = (1 << AOM_QM_BITS); + const int coeff = coeff_ptr[rc] * wt; + const int coeff_sign = (coeff >> 31); + const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; + const int prescan_add_val = + ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7); + if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) { + qcoeff_ptr[rc] = 0; + dqcoeff_ptr[rc] = 0; + *eob_ptr = 0; + } + } + } +#endif +} diff --git a/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c b/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c index 969e4e195d..0c202613dd 100644 --- a/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c +++ b/third_party/aom/aom_dsp/x86/avg_intrin_sse2.c @@ -16,6 +16,129 @@ #include "aom_dsp/x86/bitdepth_conversion_sse2.h" #include "aom_ports/mem.h" +void aom_minmax_8x8_sse2(const uint8_t *s, int p, const uint8_t *d, int dp, + int *min, int *max) { + __m128i u0, s0, d0, diff, maxabsdiff, minabsdiff, negdiff, absdiff0, absdiff; + u0 = _mm_setzero_si128(); + // Row 0 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff0 = _mm_max_epi16(diff, negdiff); + // Row 1 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(absdiff0, absdiff); + minabsdiff = _mm_min_epi16(absdiff0, absdiff); + // Row 2 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 2 * dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); + minabsdiff = _mm_min_epi16(minabsdiff, absdiff); + // Row 3 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 3 * dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); + minabsdiff = _mm_min_epi16(minabsdiff, absdiff); + // Row 4 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 4 * dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); + minabsdiff = _mm_min_epi16(minabsdiff, absdiff); + // Row 5 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 5 * dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); + minabsdiff = _mm_min_epi16(minabsdiff, absdiff); + // Row 6 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 6 * dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); + minabsdiff = _mm_min_epi16(minabsdiff, absdiff); + // Row 7 + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0); + d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 7 * dp)), u0); + diff = _mm_subs_epi16(s0, d0); + negdiff = _mm_subs_epi16(u0, diff); + absdiff = _mm_max_epi16(diff, negdiff); + maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff); + minabsdiff = _mm_min_epi16(minabsdiff, absdiff); + + maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_si128(maxabsdiff, 8)); + maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 32)); + maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 16)); + *max = _mm_extract_epi16(maxabsdiff, 0); + + minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_si128(minabsdiff, 8)); + minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 32)); + minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 16)); + *min = _mm_extract_epi16(minabsdiff, 0); +} + +unsigned int aom_avg_8x8_sse2(const uint8_t *s, int p) { + __m128i s0, s1, u0; + unsigned int avg = 0; + u0 = _mm_setzero_si128(); + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + + s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 8)); + s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 32)); + s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16)); + avg = _mm_extract_epi16(s0, 0); + return (avg + 32) >> 6; +} + +unsigned int aom_avg_4x4_sse2(const uint8_t *s, int p) { + __m128i s0, s1, u0; + unsigned int avg = 0; + u0 = _mm_setzero_si128(); + s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0); + s0 = _mm_adds_epu16(s0, s1); + + s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 4)); + s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16)); + avg = _mm_extract_epi16(s0, 0); + return (avg + 8) >> 4; +} + static void hadamard_col8_sse2(__m128i *in, int iter) { __m128i a0 = in[0]; __m128i a1 = in[1]; diff --git a/third_party/aom/aom_dsp/x86/convolve_avx2.h b/third_party/aom/aom_dsp/x86/convolve_avx2.h index e041a6230e..4a1068e835 100644 --- a/third_party/aom/aom_dsp/x86/convolve_avx2.h +++ b/third_party/aom/aom_dsp/x86/convolve_avx2.h @@ -34,31 +34,214 @@ DECLARE_ALIGNED(32, static const uint8_t, filt4_d4_global_avx2[]) = { 2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7, 5, 6, 7, 8, }; -DECLARE_ALIGNED(32, static const uint8_t, filt_center_global_avx2[32]) = { - 3, 255, 4, 255, 5, 255, 6, 255, 7, 255, 8, 255, 9, 255, 10, 255, - 3, 255, 4, 255, 5, 255, 6, 255, 7, 255, 8, 255, 9, 255, 10, 255 -}; +#define CONVOLVE_SR_HORIZONTAL_FILTER_8TAP \ + for (i = 0; i < (im_h - 2); i += 2) { \ + __m256i data = _mm256_castsi128_si256( \ + _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); \ + data = _mm256_inserti128_si256( \ + data, \ + _mm_loadu_si128( \ + (__m128i *)&src_ptr[(i * src_stride) + j + src_stride]), \ + 1); \ + \ + __m256i res = convolve_lowbd_x(data, coeffs_h, filt); \ + res = \ + _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); \ + _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); \ + } \ + \ + __m256i data_1 = _mm256_castsi128_si256( \ + _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); \ + \ + __m256i res = convolve_lowbd_x(data_1, coeffs_h, filt); \ + \ + res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); \ + \ + _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); -DECLARE_ALIGNED(32, static const uint8_t, filt1_global_avx2[32]) = { - 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 -}; +#define CONVOLVE_SR_VERTICAL_FILTER_8TAP \ + __m256i src_0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); \ + __m256i src_1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); \ + __m256i src_2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); \ + __m256i src_3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); \ + __m256i src_4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); \ + __m256i src_5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); \ + \ + __m256i s[8]; \ + s[0] = _mm256_unpacklo_epi16(src_0, src_1); \ + s[1] = _mm256_unpacklo_epi16(src_2, src_3); \ + s[2] = _mm256_unpacklo_epi16(src_4, src_5); \ + \ + s[4] = _mm256_unpackhi_epi16(src_0, src_1); \ + s[5] = _mm256_unpackhi_epi16(src_2, src_3); \ + s[6] = _mm256_unpackhi_epi16(src_4, src_5); \ + \ + for (i = 0; i < h; i += 2) { \ + const int16_t *data = &im_block[i * im_stride]; \ + \ + const __m256i s6 = _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); \ + const __m256i s7 = _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); \ + \ + s[3] = _mm256_unpacklo_epi16(s6, s7); \ + s[7] = _mm256_unpackhi_epi16(s6, s7); \ + \ + __m256i res_a = convolve(s, coeffs_v); \ + __m256i res_b = convolve(s + 4, coeffs_v); \ + \ + res_a = \ + _mm256_sra_epi32(_mm256_add_epi32(res_a, sum_round_v), sum_shift_v); \ + res_b = \ + _mm256_sra_epi32(_mm256_add_epi32(res_b, sum_round_v), sum_shift_v); \ + \ + const __m256i res_a_round = _mm256_sra_epi32( \ + _mm256_add_epi32(res_a, round_const_v), round_shift_v); \ + const __m256i res_b_round = _mm256_sra_epi32( \ + _mm256_add_epi32(res_b, round_const_v), round_shift_v); \ + \ + const __m256i res_16bit = _mm256_packs_epi32(res_a_round, res_b_round); \ + const __m256i res_8b = _mm256_packus_epi16(res_16bit, res_16bit); \ + \ + const __m128i res_0 = _mm256_castsi256_si128(res_8b); \ + const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1); \ + \ + __m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; \ + __m128i *const p_1 = (__m128i *)&dst[i * dst_stride + j + dst_stride]; \ + if (w - j > 4) { \ + _mm_storel_epi64(p_0, res_0); \ + _mm_storel_epi64(p_1, res_1); \ + } else if (w == 4) { \ + xx_storel_32(p_0, res_0); \ + xx_storel_32(p_1, res_1); \ + } else { \ + *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); \ + *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); \ + } \ + \ + s[0] = s[1]; \ + s[1] = s[2]; \ + s[2] = s[3]; \ + \ + s[4] = s[5]; \ + s[5] = s[6]; \ + s[6] = s[7]; \ + } -DECLARE_ALIGNED(32, static const uint8_t, filt2_global_avx2[32]) = { - 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10 -}; - -DECLARE_ALIGNED(32, static const uint8_t, filt3_global_avx2[32]) = { - 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, - 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12 -}; - -DECLARE_ALIGNED(32, static const uint8_t, filt4_global_avx2[32]) = { - 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, - 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14 -}; +#define DIST_WTD_CONVOLVE_HORIZONTAL_FILTER_8TAP \ + for (i = 0; i < im_h; i += 2) { \ + __m256i data = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)src_h)); \ + if (i + 1 < im_h) \ + data = _mm256_inserti128_si256( \ + data, _mm_loadu_si128((__m128i *)(src_h + src_stride)), 1); \ + src_h += (src_stride << 1); \ + __m256i res = convolve_lowbd_x(data, coeffs_x, filt); \ + \ + res = \ + _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); \ + \ + _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); \ + } +#define DIST_WTD_CONVOLVE_VERTICAL_FILTER_8TAP \ + __m256i s[8]; \ + __m256i s0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); \ + __m256i s1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); \ + __m256i s2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); \ + __m256i s3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); \ + __m256i s4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); \ + __m256i s5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); \ + \ + s[0] = _mm256_unpacklo_epi16(s0, s1); \ + s[1] = _mm256_unpacklo_epi16(s2, s3); \ + s[2] = _mm256_unpacklo_epi16(s4, s5); \ + \ + s[4] = _mm256_unpackhi_epi16(s0, s1); \ + s[5] = _mm256_unpackhi_epi16(s2, s3); \ + s[6] = _mm256_unpackhi_epi16(s4, s5); \ + \ + for (i = 0; i < h; i += 2) { \ + const int16_t *data = &im_block[i * im_stride]; \ + \ + const __m256i s6 = _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); \ + const __m256i s7 = _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); \ + \ + s[3] = _mm256_unpacklo_epi16(s6, s7); \ + s[7] = _mm256_unpackhi_epi16(s6, s7); \ + \ + const __m256i res_a = convolve(s, coeffs_y); \ + const __m256i res_a_round = _mm256_sra_epi32( \ + _mm256_add_epi32(res_a, round_const_v), round_shift_v); \ + \ + if (w - j > 4) { \ + const __m256i res_b = convolve(s + 4, coeffs_y); \ + const __m256i res_b_round = _mm256_sra_epi32( \ + _mm256_add_epi32(res_b, round_const_v), round_shift_v); \ + const __m256i res_16b = _mm256_packs_epi32(res_a_round, res_b_round); \ + const __m256i res_unsigned = _mm256_add_epi16(res_16b, offset_const); \ + \ + if (do_average) { \ + const __m256i data_ref_0 = load_line2_avx2( \ + &dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]); \ + const __m256i comp_avg_res = \ + comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); \ + \ + const __m256i round_result = convolve_rounding( \ + &comp_avg_res, &offset_const, &rounding_const, rounding_shift); \ + \ + const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); \ + const __m128i res_0 = _mm256_castsi256_si128(res_8); \ + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); \ + \ + _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); \ + _mm_storel_epi64( \ + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); \ + } else { \ + const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); \ + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); \ + \ + const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); \ + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), \ + res_1); \ + } \ + } else { \ + const __m256i res_16b = _mm256_packs_epi32(res_a_round, res_a_round); \ + const __m256i res_unsigned = _mm256_add_epi16(res_16b, offset_const); \ + \ + if (do_average) { \ + const __m256i data_ref_0 = load_line2_avx2( \ + &dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]); \ + \ + const __m256i comp_avg_res = \ + comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); \ + \ + const __m256i round_result = convolve_rounding( \ + &comp_avg_res, &offset_const, &rounding_const, rounding_shift); \ + \ + const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); \ + const __m128i res_0 = _mm256_castsi256_si128(res_8); \ + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); \ + \ + *(uint32_t *)(&dst0[i * dst_stride0 + j]) = _mm_cvtsi128_si32(res_0); \ + *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = \ + _mm_cvtsi128_si32(res_1); \ + \ + } else { \ + const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); \ + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); \ + \ + const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); \ + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), \ + res_1); \ + } \ + } \ + \ + s[0] = s[1]; \ + s[1] = s[2]; \ + s[2] = s[3]; \ + \ + s[4] = s[5]; \ + s[5] = s[6]; \ + s[6] = s[7]; \ + } static INLINE void prepare_coeffs_lowbd( const InterpFilterParams *const filter_params, const int subpel_q4, __m256i *const coeffs /* [4] */) { @@ -120,6 +303,17 @@ static INLINE __m256i convolve_lowbd(const __m256i *const s, return res; } +static INLINE __m256i convolve_lowbd_4tap(const __m256i *const s, + const __m256i *const coeffs) { + const __m256i res_23 = _mm256_maddubs_epi16(s[0], coeffs[0]); + const __m256i res_45 = _mm256_maddubs_epi16(s[1], coeffs[1]); + + // order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + const __m256i res = _mm256_add_epi16(res_45, res_23); + + return res; +} + static INLINE __m256i convolve(const __m256i *const s, const __m256i *const coeffs) { const __m256i res_0 = _mm256_madd_epi16(s[0], coeffs[0]); @@ -155,6 +349,17 @@ static INLINE __m256i convolve_lowbd_x(const __m256i data, return convolve_lowbd(s, coeffs); } +static INLINE __m256i convolve_lowbd_x_4tap(const __m256i data, + const __m256i *const coeffs, + const __m256i *const filt) { + __m256i s[2]; + + s[0] = _mm256_shuffle_epi8(data, filt[0]); + s[1] = _mm256_shuffle_epi8(data, filt[1]); + + return convolve_lowbd_4tap(s, coeffs); +} + static INLINE void add_store_aligned_256(CONV_BUF_TYPE *const dst, const __m256i *const res, const int do_average) { diff --git a/third_party/aom/aom_dsp/x86/highbd_intrapred_sse2_asm.asm b/third_party/aom/aom_dsp/x86/highbd_intrapred_sse2_asm.asm deleted file mode 100644 index 91b3d126ca..0000000000 --- a/third_party/aom/aom_dsp/x86/highbd_intrapred_sse2_asm.asm +++ /dev/null @@ -1,259 +0,0 @@ -; -; Copyright (c) 2016, 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/x86inc/x86inc.asm" - -SECTION_RODATA -pw_4: times 8 dw 4 -pw_8: times 8 dw 8 -pw_16: times 4 dd 16 -pw_32: times 4 dd 32 - -SECTION .text -INIT_XMM sse2 -cglobal highbd_dc_predictor_4x4, 4, 5, 4, dst, stride, above, left, goffset - GET_GOT goffsetq - - movq m0, [aboveq] - movq m2, [leftq] - paddw m0, m2 - pshuflw m1, m0, 0xe - paddw m0, m1 - pshuflw m1, m0, 0x1 - paddw m0, m1 - paddw m0, [GLOBAL(pw_4)] - psraw m0, 3 - pshuflw m0, m0, 0x0 - movq [dstq ], m0 - movq [dstq+strideq*2], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq*2], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal highbd_dc_predictor_8x8, 4, 5, 4, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [aboveq] - mova m2, [leftq] - DEFINE_ARGS dst, stride, stride3, one - mov oned, 0x00010001 - lea stride3q, [strideq*3] - movd m3, oned - pshufd m3, m3, 0x0 - paddw m0, m2 - pmaddwd m0, m3 - packssdw m0, m1 - pmaddwd m0, m3 - packssdw m0, m1 - pmaddwd m0, m3 - paddw m0, [GLOBAL(pw_8)] - psrlw m0, 4 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - mova [dstq ], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*4 ], m0 - mova [dstq+stride3q*2], m0 - lea dstq, [dstq+strideq*8] - mova [dstq ], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*4 ], m0 - mova [dstq+stride3q*2], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal highbd_dc_predictor_16x16, 4, 5, 5, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [aboveq] - mova m3, [aboveq+16] - mova m2, [leftq] - mova m4, [leftq+16] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 4 - paddw m0, m2 - paddw m0, m3 - paddw m0, m4 - movhlps m2, m0 - paddw m0, m2 - punpcklwd m0, m1 - movhlps m2, m0 - paddd m0, m2 - punpckldq m0, m1 - movhlps m2, m0 - paddd m0, m2 - paddd m0, [GLOBAL(pw_16)] - psrad m0, 5 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq +16], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2 +16], m0 - mova [dstq+strideq*4 ], m0 - mova [dstq+strideq*4 +16], m0 - mova [dstq+stride3q*2 ], m0 - mova [dstq+stride3q*2+16], m0 - lea dstq, [dstq+strideq*8] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal highbd_dc_predictor_32x32, 4, 5, 7, dst, stride, above, left, goffset - GET_GOT goffsetq - - mova m0, [aboveq] - mova m2, [aboveq+16] - mova m3, [aboveq+32] - mova m4, [aboveq+48] - paddw m0, m2 - paddw m3, m4 - mova m2, [leftq] - mova m4, [leftq+16] - mova m5, [leftq+32] - mova m6, [leftq+48] - paddw m2, m4 - paddw m5, m6 - paddw m0, m3 - paddw m2, m5 - pxor m1, m1 - paddw m0, m2 - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 8 - movhlps m2, m0 - paddw m0, m2 - punpcklwd m0, m1 - movhlps m2, m0 - paddd m0, m2 - punpckldq m0, m1 - movhlps m2, m0 - paddd m0, m2 - paddd m0, [GLOBAL(pw_32)] - psrad m0, 6 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq +16 ], m0 - mova [dstq +32 ], m0 - mova [dstq +48 ], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2+16 ], m0 - mova [dstq+strideq*2+32 ], m0 - mova [dstq+strideq*2+48 ], m0 - mova [dstq+strideq*4 ], m0 - mova [dstq+strideq*4+16 ], m0 - mova [dstq+strideq*4+32 ], m0 - mova [dstq+strideq*4+48 ], m0 - mova [dstq+stride3q*2 ], m0 - mova [dstq+stride3q*2 +16], m0 - mova [dstq+stride3q*2 +32], m0 - mova [dstq+stride3q*2 +48], m0 - lea dstq, [dstq+strideq*8] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal highbd_v_predictor_4x4, 3, 3, 1, dst, stride, above - movq m0, [aboveq] - movq [dstq ], m0 - movq [dstq+strideq*2], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq*2], m0 - RET - -INIT_XMM sse2 -cglobal highbd_v_predictor_8x8, 3, 3, 1, dst, stride, above - mova m0, [aboveq] - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - mova [dstq ], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*4 ], m0 - mova [dstq+stride3q*2], m0 - lea dstq, [dstq+strideq*8] - mova [dstq ], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*4 ], m0 - mova [dstq+stride3q*2], m0 - RET - -INIT_XMM sse2 -cglobal highbd_v_predictor_16x16, 3, 4, 2, dst, stride, above - mova m0, [aboveq] - mova m1, [aboveq+16] - DEFINE_ARGS dst, stride, stride3, nlines4 - lea stride3q, [strideq*3] - mov nlines4d, 4 -.loop: - mova [dstq ], m0 - mova [dstq +16], m1 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2 +16], m1 - mova [dstq+strideq*4 ], m0 - mova [dstq+strideq*4 +16], m1 - mova [dstq+stride3q*2 ], m0 - mova [dstq+stride3q*2+16], m1 - lea dstq, [dstq+strideq*8] - dec nlines4d - jnz .loop - REP_RET - -INIT_XMM sse2 -cglobal highbd_v_predictor_32x32, 3, 4, 4, dst, stride, above - mova m0, [aboveq] - mova m1, [aboveq+16] - mova m2, [aboveq+32] - mova m3, [aboveq+48] - DEFINE_ARGS dst, stride, stride3, nlines4 - lea stride3q, [strideq*3] - mov nlines4d, 8 -.loop: - mova [dstq ], m0 - mova [dstq +16], m1 - mova [dstq +32], m2 - mova [dstq +48], m3 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2 +16], m1 - mova [dstq+strideq*2 +32], m2 - mova [dstq+strideq*2 +48], m3 - mova [dstq+strideq*4 ], m0 - mova [dstq+strideq*4 +16], m1 - mova [dstq+strideq*4 +32], m2 - mova [dstq+strideq*4 +48], m3 - mova [dstq+stride3q*2 ], m0 - mova [dstq+stride3q*2 +16], m1 - mova [dstq+stride3q*2 +32], m2 - mova [dstq+stride3q*2 +48], m3 - lea dstq, [dstq+strideq*8] - dec nlines4d - jnz .loop - REP_RET diff --git a/third_party/aom/aom_dsp/x86/highbd_quantize_intrin_sse2.c b/third_party/aom/aom_dsp/x86/highbd_quantize_intrin_sse2.c index 58e5f98e58..2f4ffd3639 100644 --- a/third_party/aom/aom_dsp/x86/highbd_quantize_intrin_sse2.c +++ b/third_party/aom/aom_dsp/x86/highbd_quantize_intrin_sse2.c @@ -146,3 +146,61 @@ void aom_highbd_quantize_b_32x32_sse2( } *eob_ptr = eob + 1; } + +void aom_highbd_quantize_b_64x64_sse2( + const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, + const int16_t *round_ptr, const int16_t *quant_ptr, + const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, + tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, + const int16_t *scan, const int16_t *iscan) { + __m128i zbins[2]; + __m128i nzbins[2]; + int idx = 0; + int idx_arr[1024]; + int i, eob = -1; + const int zbin0_tmp = ROUND_POWER_OF_TWO(zbin_ptr[0], 2); + const int zbin1_tmp = ROUND_POWER_OF_TWO(zbin_ptr[1], 2); + (void)scan; + zbins[0] = _mm_set_epi32(zbin1_tmp, zbin1_tmp, zbin1_tmp, zbin0_tmp); + zbins[1] = _mm_set1_epi32(zbin1_tmp); + + nzbins[0] = _mm_setzero_si128(); + nzbins[1] = _mm_setzero_si128(); + nzbins[0] = _mm_sub_epi32(nzbins[0], zbins[0]); + nzbins[1] = _mm_sub_epi32(nzbins[1], zbins[1]); + + memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr)); + memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr)); + + // Pre-scan pass + for (i = 0; i < n_coeffs / 4; i++) { + __m128i coeffs, cmp1, cmp2; + int test; + coeffs = _mm_load_si128((const __m128i *)(coeff_ptr + i * 4)); + cmp1 = _mm_cmplt_epi32(coeffs, zbins[i != 0]); + cmp2 = _mm_cmpgt_epi32(coeffs, nzbins[i != 0]); + cmp1 = _mm_and_si128(cmp1, cmp2); + test = _mm_movemask_epi8(cmp1); + if (!(test & 0xf)) idx_arr[idx++] = i * 4; + if (!(test & 0xf0)) idx_arr[idx++] = i * 4 + 1; + if (!(test & 0xf00)) idx_arr[idx++] = i * 4 + 2; + if (!(test & 0xf000)) idx_arr[idx++] = i * 4 + 3; + } + + // Quantization pass: only process the coefficients selected in + // pre-scan pass. Note: idx can be zero. + for (i = 0; i < idx; i++) { + const int rc = idx_arr[i]; + const int coeff = coeff_ptr[rc]; + const int coeff_sign = (coeff >> 31); + const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + const int64_t tmp1 = abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 2); + const int64_t tmp2 = ((tmp1 * quant_ptr[rc != 0]) >> 16) + tmp1; + const uint32_t abs_qcoeff = + (uint32_t)((tmp2 * quant_shift_ptr[rc != 0]) >> 14); + qcoeff_ptr[rc] = (int)(abs_qcoeff ^ coeff_sign) - coeff_sign; + dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 4; + if (abs_qcoeff) eob = iscan[idx_arr[i]] > eob ? iscan[idx_arr[i]] : eob; + } + *eob_ptr = eob + 1; +} diff --git a/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c b/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c index 2373d3aecb..fc5678dda8 100644 --- a/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c +++ b/third_party/aom/aom_dsp/x86/highbd_variance_sse2.c @@ -287,30 +287,38 @@ DECLS(sse2); uint32_t aom_highbd_8_sub_pixel_variance##w##x##h##_##opt( \ const uint8_t *src8, int src_stride, int x_offset, int y_offset, \ const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr) { \ - uint32_t sse; \ uint16_t *src = CONVERT_TO_SHORTPTR(src8); \ uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \ - int se = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse, NULL, \ - NULL); \ - if (w > wf) { \ - unsigned int sse2; \ + int se = 0; \ + unsigned int sse = 0; \ + unsigned int sse2; \ + int row_rep = (w > 64) ? 2 : 1; \ + for (int wd_64 = 0; wd_64 < row_rep; wd_64++) { \ + src += wd_64 * 64; \ + dst += wd_64 * 64; \ int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \ - &sse2, NULL, NULL); \ + src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse2, \ + NULL, NULL); \ se += se2; \ sse += sse2; \ - if (w > wf * 2) { \ + if (w > wf) { \ se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, h, \ - &sse2, NULL, NULL); \ - se += se2; \ - sse += sse2; \ - se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, h, \ + src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \ &sse2, NULL, NULL); \ se += se2; \ sse += sse2; \ + if (w > wf * 2) { \ + se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, \ + h, &sse2, NULL, NULL); \ + se += se2; \ + sse += sse2; \ + se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, \ + h, &sse2, NULL, NULL); \ + se += se2; \ + sse += sse2; \ + } \ } \ } \ *sse_ptr = sse; \ @@ -322,33 +330,42 @@ DECLS(sse2); const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr) { \ int64_t var; \ uint32_t sse; \ + uint64_t long_sse = 0; \ uint16_t *src = CONVERT_TO_SHORTPTR(src8); \ uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \ - int se = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse, NULL, \ - NULL); \ - if (w > wf) { \ - uint32_t sse2; \ + int se = 0; \ + int row_rep = (w > 64) ? 2 : 1; \ + for (int wd_64 = 0; wd_64 < row_rep; wd_64++) { \ + src += wd_64 * 64; \ + dst += wd_64 * 64; \ int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \ - &sse2, NULL, NULL); \ + src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse, NULL, \ + NULL); \ se += se2; \ - sse += sse2; \ - if (w > wf * 2) { \ + long_sse += sse; \ + if (w > wf) { \ + uint32_t sse2; \ se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, h, \ + src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \ &sse2, NULL, NULL); \ se += se2; \ - sse += sse2; \ - se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, h, \ - &sse2, NULL, NULL); \ - se += se2; \ - sse += sse2; \ + long_sse += sse2; \ + if (w > wf * 2) { \ + se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, \ + h, &sse2, NULL, NULL); \ + se += se2; \ + long_sse += sse2; \ + se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, \ + h, &sse2, NULL, NULL); \ + se += se2; \ + long_sse += sse2; \ + } \ } \ } \ se = ROUND_POWER_OF_TWO(se, 2); \ - sse = ROUND_POWER_OF_TWO(sse, 4); \ + sse = (uint32_t)ROUND_POWER_OF_TWO(long_sse, 4); \ *sse_ptr = sse; \ var = (int64_t)(sse) - ((cast se * se) >> (wlog2 + hlog2)); \ return (var >= 0) ? (uint32_t)var : 0; \ @@ -364,35 +381,38 @@ DECLS(sse2); uint64_t long_sse = 0; \ uint16_t *src = CONVERT_TO_SHORTPTR(src8); \ uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \ + int row_rep = (w > 64) ? 2 : 1; \ for (start_row = 0; start_row < h; start_row += 16) { \ uint32_t sse2; \ int height = h - start_row < 16 ? h - start_row : 16; \ - int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + (start_row * src_stride), src_stride, x_offset, y_offset, \ - dst + (start_row * dst_stride), dst_stride, height, &sse2, NULL, \ - NULL); \ - se += se2; \ - long_sse += sse2; \ - if (w > wf) { \ - se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 16 + (start_row * src_stride), src_stride, x_offset, \ - y_offset, dst + 16 + (start_row * dst_stride), dst_stride, height, \ - &sse2, NULL, NULL); \ + uint16_t *src_tmp = src + (start_row * src_stride); \ + uint16_t *dst_tmp = dst + (start_row * dst_stride); \ + for (int wd_64 = 0; wd_64 < row_rep; wd_64++) { \ + src_tmp += wd_64 * 64; \ + dst_tmp += wd_64 * 64; \ + int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src_tmp, src_stride, x_offset, y_offset, dst_tmp, dst_stride, \ + height, &sse2, NULL, NULL); \ se += se2; \ long_sse += sse2; \ - if (w > wf * 2) { \ + if (w > wf) { \ se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 32 + (start_row * src_stride), src_stride, x_offset, \ - y_offset, dst + 32 + (start_row * dst_stride), dst_stride, \ - height, &sse2, NULL, NULL); \ - se += se2; \ - long_sse += sse2; \ - se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ - src + 48 + (start_row * src_stride), src_stride, x_offset, \ - y_offset, dst + 48 + (start_row * dst_stride), dst_stride, \ - height, &sse2, NULL, NULL); \ + src_tmp + 16, src_stride, x_offset, y_offset, dst_tmp + 16, \ + dst_stride, height, &sse2, NULL, NULL); \ se += se2; \ long_sse += sse2; \ + if (w > wf * 2) { \ + se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src_tmp + 32, src_stride, x_offset, y_offset, dst_tmp + 32, \ + dst_stride, height, &sse2, NULL, NULL); \ + se += se2; \ + long_sse += sse2; \ + se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \ + src_tmp + 48, src_stride, x_offset, y_offset, dst_tmp + 48, \ + dst_stride, height, &sse2, NULL, NULL); \ + se += se2; \ + long_sse += sse2; \ + } \ } \ } \ } \ @@ -403,22 +423,25 @@ DECLS(sse2); return (var >= 0) ? (uint32_t)var : 0; \ } -#define FNS(opt) \ - FN(64, 64, 16, 6, 6, opt, (int64_t)); \ - FN(64, 32, 16, 6, 5, opt, (int64_t)); \ - FN(32, 64, 16, 5, 6, opt, (int64_t)); \ - FN(32, 32, 16, 5, 5, opt, (int64_t)); \ - FN(32, 16, 16, 5, 4, opt, (int64_t)); \ - FN(16, 32, 16, 4, 5, opt, (int64_t)); \ - FN(16, 16, 16, 4, 4, opt, (int64_t)); \ - FN(16, 8, 16, 4, 3, opt, (int64_t)); \ - FN(8, 16, 8, 3, 4, opt, (int64_t)); \ - FN(8, 8, 8, 3, 3, opt, (int64_t)); \ - FN(8, 4, 8, 3, 2, opt, (int64_t)); \ - FN(16, 4, 16, 4, 2, opt, (int64_t)); \ - FN(8, 32, 8, 3, 5, opt, (int64_t)); \ - FN(32, 8, 16, 5, 3, opt, (int64_t)); \ - FN(16, 64, 16, 4, 6, opt, (int64_t)); \ +#define FNS(opt) \ + FN(128, 128, 16, 7, 7, opt, (int64_t)); \ + FN(128, 64, 16, 7, 6, opt, (int64_t)); \ + FN(64, 128, 16, 6, 7, opt, (int64_t)); \ + FN(64, 64, 16, 6, 6, opt, (int64_t)); \ + FN(64, 32, 16, 6, 5, opt, (int64_t)); \ + FN(32, 64, 16, 5, 6, opt, (int64_t)); \ + FN(32, 32, 16, 5, 5, opt, (int64_t)); \ + FN(32, 16, 16, 5, 4, opt, (int64_t)); \ + FN(16, 32, 16, 4, 5, opt, (int64_t)); \ + FN(16, 16, 16, 4, 4, opt, (int64_t)); \ + FN(16, 8, 16, 4, 3, opt, (int64_t)); \ + FN(8, 16, 8, 3, 4, opt, (int64_t)); \ + FN(8, 8, 8, 3, 3, opt, (int64_t)); \ + FN(8, 4, 8, 3, 2, opt, (int64_t)); \ + FN(16, 4, 16, 4, 2, opt, (int64_t)); \ + FN(8, 32, 8, 3, 5, opt, (int64_t)); \ + FN(32, 8, 16, 5, 3, opt, (int64_t)); \ + FN(16, 64, 16, 4, 6, opt, (int64_t)); \ FN(64, 16, 16, 6, 4, opt, (int64_t)) FNS(sse2); diff --git a/third_party/aom/aom_dsp/x86/intrapred_avx2.c b/third_party/aom/aom_dsp/x86/intrapred_avx2.c index 97569b3ed1..17f35a0b13 100644 --- a/third_party/aom/aom_dsp/x86/intrapred_avx2.c +++ b/third_party/aom/aom_dsp/x86/intrapred_avx2.c @@ -1675,7 +1675,7 @@ static void highbd_dr_prediction_z2_Nx4_avx2( // above[x+1] - above[x] // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 - __m256i a0_x, a1_x, a0_y, a1_y, a32, a16; + __m256i a0_x, a1_x, a32, a16; __m256i diff; __m128i c3f, min_base_y128; @@ -1702,16 +1702,16 @@ static void highbd_dr_prediction_z2_Nx4_avx2( } if (base_shift > 3) { - resx = _mm_setzero_si128(); + a0_x = _mm256_setzero_si256(); + a1_x = _mm256_setzero_si256(); + shift = _mm256_setzero_si256(); } else { a0_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift)); - a1_x128 = _mm_loadu_si128((__m128i *)(above + base_x + 1 + base_shift)); - if (upsample_above) { a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)HighbdEvenOddMaskx4[base_shift]); - a1_x128 = _mm_shuffle_epi8(a1_x128, - *(__m128i *)HighbdEvenOddMaskx4[base_shift]); + a1_x128 = _mm_srli_si128(a0_x128, 8); + shift = _mm256_castsi128_si256(_mm_srli_epi32( _mm_and_si128( _mm_slli_epi32( @@ -1723,8 +1723,8 @@ static void highbd_dr_prediction_z2_Nx4_avx2( } else { a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); - a1_x128 = - _mm_shuffle_epi8(a1_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); + a1_x128 = _mm_srli_si128(a0_x128, 2); + shift = _mm256_castsi128_si256(_mm_srli_epi32( _mm_and_si128(_mm_setr_epi32(-y * dx, (1 << 6) - y * dx, (2 << 6) - y * dx, (3 << 6) - y * dx), @@ -1733,22 +1733,12 @@ static void highbd_dr_prediction_z2_Nx4_avx2( } a0_x = _mm256_cvtepu16_epi32(a0_x128); a1_x = _mm256_cvtepu16_epi32(a1_x128); - - diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_x, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - resx = _mm256_castsi256_si128(res); - resx = _mm_packus_epi32(resx, resx); } // y calc + __m128i a0_y, a1_y, shifty; if (base_x < min_base_x) { - DECLARE_ALIGNED(32, int, base_y_c[4]); __m128i r6, c1234, dy128, y_c128, base_y_c128, mask128; + DECLARE_ALIGNED(32, int, base_y_c[4]); r6 = _mm_set1_epi32(r << 6); dy128 = _mm_set1_epi32(dy); c1234 = _mm_setr_epi32(1, 2, 3, 4); @@ -1758,33 +1748,36 @@ static void highbd_dr_prediction_z2_Nx4_avx2( base_y_c128 = _mm_andnot_si128(mask128, base_y_c128); _mm_store_si128((__m128i *)base_y_c, base_y_c128); - a0_y = _mm256_castsi128_si256( - _mm_setr_epi32(left[base_y_c[0]], left[base_y_c[1]], - left[base_y_c[2]], left[base_y_c[3]])); - a1_y = _mm256_castsi128_si256( - _mm_setr_epi32(left[base_y_c[0] + 1], left[base_y_c[1] + 1], - left[base_y_c[2] + 1], left[base_y_c[3] + 1])); + a0_y = _mm_setr_epi32(left[base_y_c[0]], left[base_y_c[1]], + left[base_y_c[2]], left[base_y_c[3]]); + a1_y = _mm_setr_epi32(left[base_y_c[0] + 1], left[base_y_c[1] + 1], + left[base_y_c[2] + 1], left[base_y_c[3] + 1]); if (upsample_left) { - shift = _mm256_castsi128_si256(_mm_srli_epi32( - _mm_and_si128(_mm_slli_epi32(y_c128, upsample_left), c3f), 1)); + shifty = _mm_srli_epi32( + _mm_and_si128(_mm_slli_epi32(y_c128, upsample_left), c3f), 1); } else { - shift = _mm256_castsi128_si256( - _mm_srli_epi32(_mm_and_si128(y_c128, c3f), 1)); + shifty = _mm_srli_epi32(_mm_and_si128(y_c128, c3f), 1); } - diff = _mm256_sub_epi32(a1_y, a0_y); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_y, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - resy = _mm256_castsi256_si128(res); - resy = _mm_packus_epi32(resy, resy); - } else { - resy = resx; + a0_x = _mm256_inserti128_si256(a0_x, a0_y, 1); + a1_x = _mm256_inserti128_si256(a1_x, a1_y, 1); + shift = _mm256_inserti128_si256(shift, shifty, 1); } + + diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] + a32 = _mm256_slli_epi32(a0_x, 5); // a[x] * 32 + a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi32(diff, shift); + res = _mm256_add_epi32(a32, b); + res = _mm256_srli_epi32(res, 5); + + resx = _mm256_castsi256_si128(res); + resx = _mm_packus_epi32(resx, resx); + + resy = _mm256_extracti128_si256(res, 1); + resy = _mm_packus_epi32(resy, resy); + resxy = _mm_blendv_epi8(resx, resy, *(__m128i *)HighbdBaseMask[base_min_diff]); _mm_storel_epi64((__m128i *)(dst), resxy); @@ -1792,7 +1785,7 @@ static void highbd_dr_prediction_z2_Nx4_avx2( } } -static void highbd_dr_prediction_z2_Nx8_avx2( +static void highbd_dr_prediction_32bit_z2_Nx8_avx2( int N, uint16_t *dst, ptrdiff_t stride, const uint16_t *above, const uint16_t *left, int upsample_above, int upsample_left, int dx, int dy) { @@ -1945,7 +1938,153 @@ static void highbd_dr_prediction_z2_Nx8_avx2( } } -static void highbd_dr_prediction_z2_HxW_avx2( +static void highbd_dr_prediction_z2_Nx8_avx2( + int N, uint16_t *dst, ptrdiff_t stride, const uint16_t *above, + const uint16_t *left, int upsample_above, int upsample_left, int dx, + int dy) { + const int min_base_x = -(1 << upsample_above); + const int min_base_y = -(1 << upsample_left); + const int frac_bits_x = 6 - upsample_above; + const int frac_bits_y = 6 - upsample_left; + + // pre-filter above pixels + // store in temp buffers: + // above[x] * 32 + 16 + // above[x+1] - above[x] + // final pixels will be caluculated as: + // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 + __m128i c3f, min_base_y128; + __m256i a0_x, a1_x, diff, a32, a16; + __m128i a0_x128, a1_x128; + + a16 = _mm256_set1_epi16(16); + c3f = _mm_set1_epi16(0x3f); + min_base_y128 = _mm_set1_epi16(min_base_y); + + for (int r = 0; r < N; r++) { + __m256i b, res, shift; + __m128i resx, resy, resxy; + int y = r + 1; + int base_x = (-y * dx) >> frac_bits_x; + int base_shift = 0; + if (base_x < (min_base_x - 1)) { + base_shift = (min_base_x - base_x - 1) >> upsample_above; + } + int base_min_diff = + (min_base_x - base_x + upsample_above) >> upsample_above; + if (base_min_diff > 8) { + base_min_diff = 8; + } else { + if (base_min_diff < 0) base_min_diff = 0; + } + + if (base_shift > 7) { + a0_x = _mm256_setzero_si256(); + a1_x = _mm256_setzero_si256(); + shift = _mm256_setzero_si256(); + } else { + if (upsample_above) { + a0_x128 = _mm_setr_epi16( + above[base_x + HighbdEvenOddMaskx8_2[base_shift][0]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][1]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][2]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][3]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][4]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][5]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][6]], + above[base_x + HighbdEvenOddMaskx8_2[base_shift][7]]); + a1_x128 = _mm_setr_epi16( + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][0]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][1]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][2]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][3]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][4]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][5]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][6]], + above[base_x + 1 + HighbdEvenOddMaskx8_2[base_shift][7]]); + shift = _mm256_castsi128_si256(_mm_srli_epi16( + _mm_and_si128( + _mm_slli_epi16( + _mm_setr_epi16(-y * dx, (1 << 6) - y * dx, + (2 << 6) - y * dx, (3 << 6) - y * dx, + (4 << 6) - y * dx, (5 << 6) - y * dx, + (6 << 6) - y * dx, (7 << 6) - y * dx), + upsample_above), + c3f), + 1)); + } else { + a0_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift)); + a1_x128 = _mm_loadu_si128((__m128i *)(above + base_x + 1 + base_shift)); + a0_x128 = + _mm_shuffle_epi8(a0_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); + a1_x128 = + _mm_shuffle_epi8(a1_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); + + shift = _mm256_castsi128_si256(_mm_srli_epi16( + _mm_and_si128(_mm_setr_epi16(-y * dx, (1 << 6) - y * dx, + (2 << 6) - y * dx, (3 << 6) - y * dx, + (4 << 6) - y * dx, (5 << 6) - y * dx, + (6 << 6) - y * dx, (7 << 6) - y * dx), + c3f), + 1)); + } + a0_x = _mm256_castsi128_si256(a0_x128); + a1_x = _mm256_castsi128_si256(a1_x128); + } + + // y calc + __m128i a0_y, a1_y, shifty; + if (base_x < min_base_x) { + DECLARE_ALIGNED(32, int16_t, base_y_c[16]); + __m128i r6, c1234, dy128, y_c128, base_y_c128, mask128; + r6 = _mm_set1_epi16(r << 6); + dy128 = _mm_set1_epi16(dy); + c1234 = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); + y_c128 = _mm_sub_epi16(r6, _mm_mullo_epi16(c1234, dy128)); + base_y_c128 = _mm_srai_epi16(y_c128, frac_bits_y); + mask128 = _mm_cmpgt_epi16(min_base_y128, base_y_c128); + base_y_c128 = _mm_andnot_si128(mask128, base_y_c128); + _mm_store_si128((__m128i *)base_y_c, base_y_c128); + + a0_y = _mm_setr_epi16(left[base_y_c[0]], left[base_y_c[1]], + left[base_y_c[2]], left[base_y_c[3]], + left[base_y_c[4]], left[base_y_c[5]], + left[base_y_c[6]], left[base_y_c[7]]); + a1_y = _mm_setr_epi16(left[base_y_c[0] + 1], left[base_y_c[1] + 1], + left[base_y_c[2] + 1], left[base_y_c[3] + 1], + left[base_y_c[4] + 1], left[base_y_c[5] + 1], + left[base_y_c[6] + 1], left[base_y_c[7] + 1]); + + if (upsample_left) { + shifty = _mm_srli_epi16( + _mm_and_si128(_mm_slli_epi16((y_c128), upsample_left), c3f), 1); + } else { + shifty = _mm_srli_epi16(_mm_and_si128(y_c128, c3f), 1); + } + a0_x = _mm256_inserti128_si256(a0_x, a0_y, 1); + a1_x = _mm256_inserti128_si256(a1_x, a1_y, 1); + shift = _mm256_inserti128_si256(shift, shifty, 1); + } + + diff = _mm256_sub_epi16(a1_x, a0_x); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0_x, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi16(diff, shift); + res = _mm256_add_epi16(a32, b); + res = _mm256_srli_epi16(res, 5); + + resx = _mm256_castsi256_si128(res); + resy = _mm256_extracti128_si256(res, 1); + + resxy = + _mm_blendv_epi8(resx, resy, *(__m128i *)HighbdBaseMask[base_min_diff]); + _mm_storeu_si128((__m128i *)(dst), resxy); + dst += stride; + } +} + +static void highbd_dr_prediction_32bit_z2_HxW_avx2( int H, int W, uint16_t *dst, ptrdiff_t stride, const uint16_t *above, const uint16_t *left, int upsample_above, int upsample_left, int dx, int dy) { @@ -1971,6 +2110,7 @@ static void highbd_dr_prediction_z2_HxW_avx2( a16 = _mm256_set1_epi32(16); min_base_y256 = _mm256_set1_epi16(min_base_y); c3f = _mm256_set1_epi32(0x3f); + for (int r = 0; r < H; r++) { __m256i b, res, shift; __m256i resx[2], resy[2]; @@ -2010,7 +2150,7 @@ static void highbd_dr_prediction_z2_HxW_avx2( ((2 + j) << 6) - y * dx, ((3 + j) << 6) - y * dx, ((4 + j) << 6) - y * dx, ((5 + j) << 6) - y * dx, ((6 + j) << 6) - y * dx, ((7 + j) << 6) - y * dx), - _mm256_set1_epi32(0x3f)), + c3f), 1); diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] @@ -2024,21 +2164,21 @@ static void highbd_dr_prediction_z2_HxW_avx2( resx[0] = _mm256_packus_epi32( res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); } - base_shift = 0; + int base_shift8 = 0; if ((base_x + j + 8) < (min_base_x - 1)) { - base_shift = (min_base_x - (base_x + j + 8) - 1); + base_shift8 = (min_base_x - (base_x + j + 8) - 1); } - if (base_shift > 7) { + if (base_shift8 > 7) { resx[1] = _mm256_setzero_si256(); } else { a0_1_x128 = - _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 8 + j)); + _mm_loadu_si128((__m128i *)(above + base_x + base_shift8 + 8 + j)); a1_1_x128 = - _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 9 + j)); + _mm_loadu_si128((__m128i *)(above + base_x + base_shift8 + 9 + j)); a0_1_x128 = _mm_shuffle_epi8(a0_1_x128, - *(__m128i *)HighbdLoadMaskx[base_shift]); + *(__m128i *)HighbdLoadMaskx[base_shift8]); a1_1_x128 = _mm_shuffle_epi8(a1_1_x128, - *(__m128i *)HighbdLoadMaskx[base_shift]); + *(__m128i *)HighbdLoadMaskx[base_shift8]); a0_1_x = _mm256_cvtepu16_epi32(a0_1_x128); a1_1_x = _mm256_cvtepu16_epi32(a1_1_x128); @@ -2050,7 +2190,7 @@ static void highbd_dr_prediction_z2_HxW_avx2( ((10 + j) << 6) - y * dx, ((11 + j) << 6) - y * dx, ((12 + j) << 6) - y * dx, ((13 + j) << 6) - y * dx, ((14 + j) << 6) - y * dx, ((15 + j) << 6) - y * dx), - _mm256_set1_epi32(0x3f)), + c3f), 1); diff = _mm256_sub_epi32(a1_1_x, a0_1_x); // a[x+1] - a[x] @@ -2147,6 +2287,170 @@ static void highbd_dr_prediction_z2_HxW_avx2( } } +static void highbd_dr_prediction_z2_HxW_avx2( + int H, int W, uint16_t *dst, ptrdiff_t stride, const uint16_t *above, + const uint16_t *left, int upsample_above, int upsample_left, int dx, + int dy) { + // here upsample_above and upsample_left are 0 by design of + // av1_use_intra_edge_upsample + const int min_base_x = -1; + const int min_base_y = -1; + (void)upsample_above; + (void)upsample_left; + const int frac_bits_x = 6; + const int frac_bits_y = 6; + + // pre-filter above pixels + // store in temp buffers: + // above[x] * 32 + 16 + // above[x+1] - above[x] + // final pixels will be caluculated as: + // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 + __m256i a0_x, a1_x, a32, a16, c3f; + __m256i diff, min_base_y256; + + a16 = _mm256_set1_epi16(16); + min_base_y256 = _mm256_set1_epi16(min_base_y); + c3f = _mm256_set1_epi16(0x3f); + + for (int r = 0; r < H; r++) { + __m256i b, res, shift; + __m256i resx, resy; + __m256i resxy; + __m128i a0_x128, a1_x128, a0_1_x128, a1_1_x128, shiftx; + + for (int j = 0; j < W; j += 16) { + int y = r + 1; + int base_x = (-y * dx) >> frac_bits_x; + int base_shift = 0; + if ((base_x + j) < (min_base_x - 1)) { + base_shift = (min_base_x - (base_x + j) - 1); + } + int base_min_diff = (min_base_x - base_x - j); + if (base_min_diff > 16) { + base_min_diff = 16; + } else { + if (base_min_diff < 0) base_min_diff = 0; + } + + if (base_shift > 7) { + a0_x = _mm256_setzero_si256(); + a1_x = _mm256_setzero_si256(); + shift = _mm256_setzero_si256(); + } else { + a0_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift + j)); + a1_x128 = + _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 1 + j)); + a0_x128 = + _mm_shuffle_epi8(a0_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); + a1_x128 = + _mm_shuffle_epi8(a1_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); + + a0_x = _mm256_castsi128_si256(a0_x128); + a1_x = _mm256_castsi128_si256(a1_x128); + + shift = _mm256_castsi128_si256(_mm_srli_epi16( + _mm_and_si128(_mm_setr_epi16( + ((0 + j) << 6) - y * dx, ((1 + j) << 6) - y * dx, + ((2 + j) << 6) - y * dx, ((3 + j) << 6) - y * dx, + ((4 + j) << 6) - y * dx, ((5 + j) << 6) - y * dx, + ((6 + j) << 6) - y * dx, ((7 + j) << 6) - y * dx), + _mm256_castsi256_si128(c3f)), + 1)); + } + + base_shift = 0; + if ((base_x + j + 8) < (min_base_x - 1)) { + base_shift = (min_base_x - (base_x + j + 8) - 1); + } + if (base_shift <= 7) { + a0_1_x128 = + _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 8 + j)); + a1_1_x128 = + _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 9 + j)); + a0_1_x128 = _mm_shuffle_epi8(a0_1_x128, + *(__m128i *)HighbdLoadMaskx[base_shift]); + a1_1_x128 = _mm_shuffle_epi8(a1_1_x128, + *(__m128i *)HighbdLoadMaskx[base_shift]); + + shiftx = _mm_srli_epi16( + _mm_and_si128( + _mm_setr_epi16( + ((8 + j) << 6) - y * dx, ((9 + j) << 6) - y * dx, + ((10 + j) << 6) - y * dx, ((11 + j) << 6) - y * dx, + ((12 + j) << 6) - y * dx, ((13 + j) << 6) - y * dx, + ((14 + j) << 6) - y * dx, ((15 + j) << 6) - y * dx), + _mm256_castsi256_si128(c3f)), + 1); + + a0_x = _mm256_inserti128_si256(a0_x, a0_1_x128, 1); + a1_x = _mm256_inserti128_si256(a1_x, a1_1_x128, 1); + shift = _mm256_inserti128_si256(shift, shiftx, 1); + } + + diff = _mm256_sub_epi16(a1_x, a0_x); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0_x, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi16(diff, shift); + res = _mm256_add_epi16(a32, b); + resx = _mm256_srli_epi16(res, 5); // 16 16-bit values + + // y calc + __m256i a0_y, a1_y, shifty; + if ((base_x < min_base_x)) { + DECLARE_ALIGNED(32, int16_t, base_y_c[16]); + __m256i r6, c256, dy256, y_c256, base_y_c256, mask256, mul16; + r6 = _mm256_set1_epi16(r << 6); + dy256 = _mm256_set1_epi16(dy); + c256 = _mm256_setr_epi16(1 + j, 2 + j, 3 + j, 4 + j, 5 + j, 6 + j, + 7 + j, 8 + j, 9 + j, 10 + j, 11 + j, 12 + j, + 13 + j, 14 + j, 15 + j, 16 + j); + mul16 = _mm256_min_epu16(_mm256_mullo_epi16(c256, dy256), + _mm256_srli_epi16(min_base_y256, 1)); + y_c256 = _mm256_sub_epi16(r6, mul16); + base_y_c256 = _mm256_srai_epi16(y_c256, frac_bits_y); + mask256 = _mm256_cmpgt_epi16(min_base_y256, base_y_c256); + base_y_c256 = _mm256_andnot_si256(mask256, base_y_c256); + _mm256_store_si256((__m256i *)base_y_c, base_y_c256); + + a0_y = _mm256_setr_epi16( + left[base_y_c[0]], left[base_y_c[1]], left[base_y_c[2]], + left[base_y_c[3]], left[base_y_c[4]], left[base_y_c[5]], + left[base_y_c[6]], left[base_y_c[7]], left[base_y_c[8]], + left[base_y_c[9]], left[base_y_c[10]], left[base_y_c[11]], + left[base_y_c[12]], left[base_y_c[13]], left[base_y_c[14]], + left[base_y_c[15]]); + a1_y = _mm256_setr_epi16( + left[base_y_c[0] + 1], left[base_y_c[1] + 1], left[base_y_c[2] + 1], + left[base_y_c[3] + 1], left[base_y_c[4] + 1], left[base_y_c[5] + 1], + left[base_y_c[6] + 1], left[base_y_c[7] + 1], left[base_y_c[8] + 1], + left[base_y_c[9] + 1], left[base_y_c[10] + 1], + left[base_y_c[11] + 1], left[base_y_c[12] + 1], + left[base_y_c[13] + 1], left[base_y_c[14] + 1], + left[base_y_c[15] + 1]); + + shifty = _mm256_srli_epi16(_mm256_and_si256(y_c256, c3f), 1); + + diff = _mm256_sub_epi16(a1_y, a0_y); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0_y, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi16(diff, shifty); + res = _mm256_add_epi16(a32, b); + resy = _mm256_srli_epi16(res, 5); + } else { + resy = _mm256_setzero_si256(); + } + + resxy = _mm256_blendv_epi8(resx, resy, + *(__m256i *)HighbdBaseMask[base_min_diff]); + _mm256_storeu_si256((__m256i *)(dst + j), resxy); + } // for j + dst += stride; + } +} + // Directional prediction, zone 2: 90 < angle < 180 void av1_highbd_dr_prediction_z2_avx2(uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, @@ -2162,15 +2466,26 @@ void av1_highbd_dr_prediction_z2_avx2(uint16_t *dst, ptrdiff_t stride, int bw, upsample_above, upsample_left, dx, dy); break; case 8: - highbd_dr_prediction_z2_Nx8_avx2(bh, dst, stride, above, left, - upsample_above, upsample_left, dx, dy); + if (bd < 12) { + highbd_dr_prediction_z2_Nx8_avx2(bh, dst, stride, above, left, + upsample_above, upsample_left, dx, dy); + } else { + highbd_dr_prediction_32bit_z2_Nx8_avx2(bh, dst, stride, above, left, + upsample_above, upsample_left, + dx, dy); + } break; default: - highbd_dr_prediction_z2_HxW_avx2(bh, bw, dst, stride, above, left, - upsample_above, upsample_left, dx, dy); + if (bd < 12) { + highbd_dr_prediction_z2_HxW_avx2(bh, bw, dst, stride, above, left, + upsample_above, upsample_left, dx, dy); + } else { + highbd_dr_prediction_32bit_z2_HxW_avx2(bh, bw, dst, stride, above, left, + upsample_above, upsample_left, + dx, dy); + } break; } - return; } static void highbd_transpose(const uint16_t *src, ptrdiff_t pitchSrc, @@ -2244,7 +2559,7 @@ static void highbd_dr_prediction_z3_8x4_avx2(uint16_t *dst, ptrdiff_t stride, static void highbd_dr_prediction_z3_8x16_avx2(uint16_t *dst, ptrdiff_t stride, const uint16_t *left, int upsample_left, int dy) { - __m256i dstvec[8], d[16]; + __m256i dstvec[8], d[8]; highbd_dr_prediction_z1_16xN_internal_avx2(8, dstvec, left, upsample_left, dy); @@ -2716,11 +3031,12 @@ static AOM_FORCE_INLINE void dr_prediction_z1_4xN_internal_avx2( // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 __m256i a0, a1, a32, a16; - __m256i diff; + __m256i diff, c3f; __m128i a_mbase_x; - a16 = _mm256_set1_epi32(16); + a16 = _mm256_set1_epi16(16); a_mbase_x = _mm_set1_epi8(above[max_base_x]); + c3f = _mm256_set1_epi16(0x3f); x = dx; for (int r = 0; r < N; r++) { @@ -2738,33 +3054,32 @@ static AOM_FORCE_INLINE void dr_prediction_z1_4xN_internal_avx2( if (base_max_diff > 4) base_max_diff = 4; a0_128 = _mm_loadu_si128((__m128i *)(above + base)); a1_128 = _mm_srli_si128(a0_128, 1); - a0 = _mm256_cvtepu8_epi32(a0_128); - a1 = _mm256_cvtepu8_epi32(a1_128); if (upsample_above) { - a0 = _mm256_permutevar8x32_epi32( - a0, _mm256_set_epi32(7, 5, 3, 1, 6, 4, 2, 0)); - a1 = _mm256_castsi128_si256(_mm256_extracti128_si256(a0, 1)); - shift = _mm256_srli_epi32( + a0_128 = _mm_shuffle_epi8( + a0_128, + _mm_setr_epi8(0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15)); + a1_128 = _mm_srli_si128(a0_128, 4); + + shift = _mm256_srli_epi16( _mm256_and_si256( - _mm256_slli_epi32(_mm256_set1_epi32(x), upsample_above), - _mm256_set1_epi32(0x3f)), + _mm256_slli_epi16(_mm256_set1_epi16(x), upsample_above), c3f), 1); } else { - shift = _mm256_srli_epi32( - _mm256_and_si256(_mm256_set1_epi32(x), _mm256_set1_epi32(0x3f)), 1); + shift = _mm256_srli_epi16(_mm256_and_si256(_mm256_set1_epi16(x), c3f), 1); } + a0 = _mm256_cvtepu8_epi16(a0_128); + a1 = _mm256_cvtepu8_epi16(a1_128); - diff = _mm256_sub_epi32(a1, a0); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 + diff = _mm256_sub_epi16(a1, a0); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); + b = _mm256_mullo_epi16(diff, shift); + res = _mm256_add_epi16(a32, b); + res = _mm256_srli_epi16(res, 5); res1 = _mm256_castsi256_si128(res); - res1 = _mm_packus_epi32(res1, res1); res1 = _mm_packus_epi16(res1, res1); dst[r] = @@ -2796,11 +3111,12 @@ static AOM_FORCE_INLINE void dr_prediction_z1_8xN_internal_avx2( // above[x+1] - above[x] // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 - __m256i a0, a1, a0_1, a1_1, a32, a16, diff; + __m256i a0, a1, a0_1, a1_1, a32, a16, diff, c3f; __m128i a_mbase_x; a16 = _mm256_set1_epi32(16); a_mbase_x = _mm_set1_epi8(above[max_base_x]); + c3f = _mm256_set1_epi32(0x3f); x = dx; for (int r = 0; r < N; r++) { @@ -2836,12 +3152,10 @@ static AOM_FORCE_INLINE void dr_prediction_z1_8xN_internal_avx2( shift = _mm256_srli_epi32( _mm256_and_si256( - _mm256_slli_epi32(_mm256_set1_epi32(x), upsample_above), - _mm256_set1_epi32(0x3f)), + _mm256_slli_epi32(_mm256_set1_epi32(x), upsample_above), c3f), 1); } else { - shift = _mm256_srli_epi32( - _mm256_and_si256(_mm256_set1_epi32(x), _mm256_set1_epi32(0x3f)), 1); + shift = _mm256_srli_epi32(_mm256_and_si256(_mm256_set1_epi32(x), c3f), 1); } diff = _mm256_sub_epi32(a1, a0); // a[x+1] - a[x] @@ -2891,11 +3205,12 @@ static AOM_FORCE_INLINE void dr_prediction_z1_16xN_internal_avx2( // above[x+1] - above[x] // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 - __m256i a0, a0_1, a1, a1_1, diff, a32, a16; + __m256i a0, a0_1, a1, a1_1, diff, a32, a16, c3f; __m128i a_mbase_x; a16 = _mm256_set1_epi32(16); a_mbase_x = _mm_set1_epi8((uint8_t)above[max_base_x]); + c3f = _mm256_set1_epi32(0x3f); x = dx; for (int r = 0; r < N; r++) { @@ -2909,8 +3224,8 @@ static AOM_FORCE_INLINE void dr_prediction_z1_16xN_internal_avx2( } return; } - __m256i shift = _mm256_srli_epi32( - _mm256_and_si256(_mm256_set1_epi32(x), _mm256_set1_epi32(0x3f)), 1); + __m256i shift = + _mm256_srli_epi32(_mm256_and_si256(_mm256_set1_epi32(x), c3f), 1); a0 = _mm256_cvtepu8_epi32(_mm_loadu_si128((__m128i *)(above + base))); a1 = _mm256_cvtepu8_epi32(_mm_loadu_si128((__m128i *)(above + base + 1))); @@ -2983,10 +3298,11 @@ static AOM_FORCE_INLINE void dr_prediction_z1_32xN_internal_avx2( // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 __m256i a0, a0_1, a1, a1_1, a32, a16; - __m256i a_mbase_x, diff; + __m256i a_mbase_x, diff, c3f; a16 = _mm256_set1_epi32(16); a_mbase_x = _mm256_set1_epi8(above[max_base_x]); + c3f = _mm256_set1_epi32(0x3f); x = dx; for (int r = 0; r < N; r++) { @@ -3001,8 +3317,8 @@ static AOM_FORCE_INLINE void dr_prediction_z1_32xN_internal_avx2( return; } if (base_max_diff > 32) base_max_diff = 32; - __m256i shift = _mm256_srli_epi32( - _mm256_and_si256(_mm256_set1_epi32(x), _mm256_set1_epi32(0x3f)), 1); + __m256i shift = + _mm256_srli_epi32(_mm256_and_si256(_mm256_set1_epi32(x), c3f), 1); for (int j = 0, jj = 0; j < 32; j += 16, jj++) { int mdiff = base_max_diff - j; @@ -3077,7 +3393,6 @@ static void dr_prediction_z1_64xN_avx2(int N, uint8_t *dst, ptrdiff_t stride, const uint8_t *above, int upsample_above, int dx) { int x; - // here upsample_above is 0 by design of av1_use_intra_edge_upsample (void)upsample_above; const int frac_bits = 6; @@ -3090,12 +3405,13 @@ static void dr_prediction_z1_64xN_avx2(int N, uint8_t *dst, ptrdiff_t stride, // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 __m256i a0, a0_1, a1, a1_1, a32, a16; - __m256i a_mbase_x, diff; + __m256i a_mbase_x, diff, c3f; __m128i max_base_x128, base_inc128, mask128; a16 = _mm256_set1_epi32(16); a_mbase_x = _mm256_set1_epi8(above[max_base_x]); max_base_x128 = _mm_set1_epi8(max_base_x); + c3f = _mm256_set1_epi32(0x3f); x = dx; for (int r = 0; r < N; r++, dst += stride) { @@ -3112,8 +3428,8 @@ static void dr_prediction_z1_64xN_avx2(int N, uint8_t *dst, ptrdiff_t stride, return; } - __m256i shift = _mm256_srli_epi32( - _mm256_and_si256(_mm256_set1_epi32(x), _mm256_set1_epi32(0x3f)), 1); + __m256i shift = + _mm256_srli_epi32(_mm256_and_si256(_mm256_set1_epi32(x), c3f), 1); __m128i a0_128, a0_1_128, a1_128, a1_1_128; for (int j = 0; j < 64; j += 16) { @@ -3258,7 +3574,7 @@ static void dr_prediction_z2_Nx4_avx2(int N, uint8_t *dst, ptrdiff_t stride, // above[x+1] - above[x] // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 - __m256i a0_x, a1_x, a0_y, a1_y, a32, a16, diff; + __m256i a0_x, a1_x, a32, a16, diff; __m128i c3f, min_base_y128; a16 = _mm256_set1_epi32(16); @@ -3284,7 +3600,9 @@ static void dr_prediction_z2_Nx4_avx2(int N, uint8_t *dst, ptrdiff_t stride, } if (base_shift > 3) { - resx = _mm_setzero_si128(); + a0_x = _mm256_setzero_si256(); + a1_x = _mm256_setzero_si256(); + shift = _mm256_setzero_si256(); } else { a0_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift)); if (upsample_above) { @@ -3303,6 +3621,7 @@ static void dr_prediction_z2_Nx4_avx2(int N, uint8_t *dst, ptrdiff_t stride, } else { a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)LoadMaskx[base_shift]); a1_x128 = _mm_srli_si128(a0_x128, 1); + shift = _mm256_castsi128_si256(_mm_srli_epi32( _mm_and_si128(_mm_setr_epi32(-y * dx, (1 << 6) - y * dx, (2 << 6) - y * dx, (3 << 6) - y * dx), @@ -3311,20 +3630,9 @@ static void dr_prediction_z2_Nx4_avx2(int N, uint8_t *dst, ptrdiff_t stride, } a0_x = _mm256_cvtepu8_epi32(a0_x128); a1_x = _mm256_cvtepu8_epi32(a1_x128); - - diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_x, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - resx = _mm256_castsi256_si128(res); - resx = _mm_packus_epi32(resx, resx); - resx = _mm_packus_epi16(resx, resx); } // y calc + __m128i a0_y, a1_y, shifty; if (base_x < min_base_x) { DECLARE_ALIGNED(32, int, base_y_c[4]); __m128i r6, c1234, dy128, y_c128, base_y_c128, mask128; @@ -3337,34 +3645,38 @@ static void dr_prediction_z2_Nx4_avx2(int N, uint8_t *dst, ptrdiff_t stride, base_y_c128 = _mm_andnot_si128(mask128, base_y_c128); _mm_store_si128((__m128i *)base_y_c, base_y_c128); - a0_y = _mm256_castsi128_si256( - _mm_setr_epi32(left[base_y_c[0]], left[base_y_c[1]], - left[base_y_c[2]], left[base_y_c[3]])); - a1_y = _mm256_castsi128_si256( - _mm_setr_epi32(left[base_y_c[0] + 1], left[base_y_c[1] + 1], - left[base_y_c[2] + 1], left[base_y_c[3] + 1])); + a0_y = _mm_setr_epi32(left[base_y_c[0]], left[base_y_c[1]], + left[base_y_c[2]], left[base_y_c[3]]); + a1_y = _mm_setr_epi32(left[base_y_c[0] + 1], left[base_y_c[1] + 1], + left[base_y_c[2] + 1], left[base_y_c[3] + 1]); if (upsample_left) { - shift = _mm256_castsi128_si256(_mm_srli_epi32( - _mm_and_si128(_mm_slli_epi32(y_c128, upsample_left), c3f), 1)); + shifty = _mm_srli_epi32( + _mm_and_si128(_mm_slli_epi32(y_c128, upsample_left), c3f), 1); } else { - shift = _mm256_castsi128_si256( - _mm_srli_epi32(_mm_and_si128(y_c128, c3f), 1)); + shifty = _mm_srli_epi32(_mm_and_si128(y_c128, c3f), 1); } - diff = _mm256_sub_epi32(a1_y, a0_y); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_y, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - resy = _mm256_castsi256_si128(res); - resy = _mm_packus_epi32(resy, resy); - resy = _mm_packus_epi16(resy, resy); - } else { - resy = resx; + a0_x = _mm256_inserti128_si256(a0_x, a0_y, 1); + a1_x = _mm256_inserti128_si256(a1_x, a1_y, 1); + shift = _mm256_inserti128_si256(shift, shifty, 1); } + + diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] + a32 = _mm256_slli_epi32(a0_x, 5); // a[x] * 32 + a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi32(diff, shift); + res = _mm256_add_epi32(a32, b); + res = _mm256_srli_epi32(res, 5); + + resx = _mm256_castsi256_si128(res); + resx = _mm_packus_epi32(resx, resx); + resx = _mm_packus_epi16(resx, resx); + + resy = _mm256_extracti128_si256(res, 1); + resy = _mm_packus_epi32(resy, resy); + resy = _mm_packus_epi16(resy, resy); + resxy = _mm_blendv_epi8(resx, resy, *(__m128i *)BaseMask[base_min_diff]); *(uint32_t *)(dst) = _mm_cvtsi128_si32(resxy); dst += stride; @@ -3386,13 +3698,13 @@ static void dr_prediction_z2_Nx8_avx2(int N, uint8_t *dst, ptrdiff_t stride, // above[x+1] - above[x] // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 - __m256i a0_x, a1_x, a0_y, a1_y, a32, a16, c3f; - __m256i diff, min_base_y256; - __m128i a0_x128, a1_x128; + __m256i diff, a32, a16; + __m256i a0_x, a1_x; + __m128i a0_x128, a1_x128, min_base_y128, c3f; - a16 = _mm256_set1_epi32(16); - c3f = _mm256_set1_epi32(0x3f); - min_base_y256 = _mm256_set1_epi32(min_base_y); + a16 = _mm256_set1_epi16(16); + c3f = _mm_set1_epi16(0x3f); + min_base_y128 = _mm_set1_epi16(min_base_y); for (int r = 0; r < N; r++) { __m256i b, res, shift; @@ -3413,7 +3725,9 @@ static void dr_prediction_z2_Nx8_avx2(int N, uint8_t *dst, ptrdiff_t stride, } if (base_shift > 7) { - resx = _mm_setzero_si128(); + a0_x = _mm256_setzero_si256(); + a1_x = _mm256_setzero_si256(); + shift = _mm256_setzero_si256(); } else { a0_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift)); a1_x128 = _mm_loadu_si128((__m128i *)(above + base_x + 1 + base_shift)); @@ -3423,88 +3737,80 @@ static void dr_prediction_z2_Nx8_avx2(int N, uint8_t *dst, ptrdiff_t stride, a1_x128 = _mm_shuffle_epi8(a1_x128, *(__m128i *)EvenOddMaskx[base_shift]); - shift = _mm256_srli_epi32( - _mm256_and_si256( - _mm256_slli_epi32( - _mm256_setr_epi32(-y * dx, (1 << 6) - y * dx, - (2 << 6) - y * dx, (3 << 6) - y * dx, - (4 << 6) - y * dx, (5 << 6) - y * dx, - (6 << 6) - y * dx, (7 << 6) - y * dx), + shift = _mm256_castsi128_si256(_mm_srli_epi16( + _mm_and_si128( + _mm_slli_epi16( + _mm_setr_epi16(-y * dx, (1 << 6) - y * dx, + (2 << 6) - y * dx, (3 << 6) - y * dx, + (4 << 6) - y * dx, (5 << 6) - y * dx, + (6 << 6) - y * dx, (7 << 6) - y * dx), upsample_above), c3f), - 1); + 1)); } else { a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)LoadMaskx[base_shift]); a1_x128 = _mm_shuffle_epi8(a1_x128, *(__m128i *)LoadMaskx[base_shift]); - shift = _mm256_srli_epi32( - _mm256_and_si256( - _mm256_setr_epi32(-y * dx, (1 << 6) - y * dx, (2 << 6) - y * dx, - (3 << 6) - y * dx, (4 << 6) - y * dx, - (5 << 6) - y * dx, (6 << 6) - y * dx, - (7 << 6) - y * dx), - c3f), - 1); + shift = _mm256_castsi128_si256(_mm_srli_epi16( + _mm_and_si128(_mm_setr_epi16(-y * dx, (1 << 6) - y * dx, + (2 << 6) - y * dx, (3 << 6) - y * dx, + (4 << 6) - y * dx, (5 << 6) - y * dx, + (6 << 6) - y * dx, (7 << 6) - y * dx), + c3f), + 1)); } - a0_x = _mm256_cvtepu8_epi32(a0_x128); - a1_x = _mm256_cvtepu8_epi32(a1_x128); - - diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_x, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - res = _mm256_packus_epi32( - res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); - resx = _mm_packus_epi16(_mm256_castsi256_si128(res), - _mm256_castsi256_si128(res)); + a0_x = _mm256_castsi128_si256(_mm_cvtepu8_epi16(a0_x128)); + a1_x = _mm256_castsi128_si256(_mm_cvtepu8_epi16(a1_x128)); } - // y calc - if (base_x < min_base_x) { - DECLARE_ALIGNED(32, int, base_y_c[8]); - __m256i r6, c256, dy256, y_c256, base_y_c256, mask256; - r6 = _mm256_set1_epi32(r << 6); - dy256 = _mm256_set1_epi32(dy); - c256 = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8); - y_c256 = _mm256_sub_epi32(r6, _mm256_mullo_epi32(c256, dy256)); - base_y_c256 = _mm256_srai_epi32(y_c256, frac_bits_y); - mask256 = _mm256_cmpgt_epi32(min_base_y256, base_y_c256); - base_y_c256 = _mm256_andnot_si256(mask256, base_y_c256); - _mm256_store_si256((__m256i *)base_y_c, base_y_c256); - a0_y = _mm256_setr_epi32(left[base_y_c[0]], left[base_y_c[1]], - left[base_y_c[2]], left[base_y_c[3]], - left[base_y_c[4]], left[base_y_c[5]], - left[base_y_c[6]], left[base_y_c[7]]); - a1_y = _mm256_setr_epi32(left[base_y_c[0] + 1], left[base_y_c[1] + 1], - left[base_y_c[2] + 1], left[base_y_c[3] + 1], - left[base_y_c[4] + 1], left[base_y_c[5] + 1], - left[base_y_c[6] + 1], left[base_y_c[7] + 1]); + // y calc + __m128i a0_y, a1_y, shifty; + if (base_x < min_base_x) { + DECLARE_ALIGNED(32, int16_t, base_y_c[16]); + __m128i r6, c1234, dy128, y_c128, base_y_c128, mask128; + r6 = _mm_set1_epi16(r << 6); + dy128 = _mm_set1_epi16(dy); + c1234 = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); + y_c128 = _mm_sub_epi16(r6, _mm_mullo_epi16(c1234, dy128)); + base_y_c128 = _mm_srai_epi16(y_c128, frac_bits_y); + mask128 = _mm_cmpgt_epi16(min_base_y128, base_y_c128); + base_y_c128 = _mm_andnot_si128(mask128, base_y_c128); + _mm_store_si128((__m128i *)base_y_c, base_y_c128); + + a0_y = _mm_setr_epi16(left[base_y_c[0]], left[base_y_c[1]], + left[base_y_c[2]], left[base_y_c[3]], + left[base_y_c[4]], left[base_y_c[5]], + left[base_y_c[6]], left[base_y_c[7]]); + a1_y = _mm_setr_epi16(left[base_y_c[0] + 1], left[base_y_c[1] + 1], + left[base_y_c[2] + 1], left[base_y_c[3] + 1], + left[base_y_c[4] + 1], left[base_y_c[5] + 1], + left[base_y_c[6] + 1], left[base_y_c[7] + 1]); if (upsample_left) { - shift = _mm256_srli_epi32( - _mm256_and_si256(_mm256_slli_epi32(y_c256, upsample_left), c3f), 1); + shifty = _mm_srli_epi16( + _mm_and_si128(_mm_slli_epi16(y_c128, upsample_left), c3f), 1); } else { - shift = _mm256_srli_epi32(_mm256_and_si256(y_c256, c3f), 1); + shifty = _mm_srli_epi16(_mm_and_si128(y_c128, c3f), 1); } - diff = _mm256_sub_epi32(a1_y, a0_y); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_y, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - res = _mm256_packus_epi32( - res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); - resy = _mm_packus_epi16(_mm256_castsi256_si128(res), - _mm256_castsi256_si128(res)); - } else { - resy = resx; + a0_x = _mm256_inserti128_si256(a0_x, a0_y, 1); + a1_x = _mm256_inserti128_si256(a1_x, a1_y, 1); + shift = _mm256_inserti128_si256(shift, shifty, 1); } + + diff = _mm256_sub_epi16(a1_x, a0_x); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0_x, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi16(diff, shift); + res = _mm256_add_epi16(a32, b); + res = _mm256_srli_epi16(res, 5); + + resx = _mm_packus_epi16(_mm256_castsi256_si128(res), + _mm256_castsi256_si128(res)); + resy = _mm256_extracti128_si256(res, 1); + resy = _mm_packus_epi16(resy, resy); + resxy = _mm_blendv_epi8(resx, resy, *(__m128i *)BaseMask[base_min_diff]); _mm_storel_epi64((__m128i *)(dst), resxy); dst += stride; @@ -3530,17 +3836,17 @@ static void dr_prediction_z2_HxW_avx2(int H, int W, uint8_t *dst, // above[x+1] - above[x] // final pixels will be caluculated as: // (above[x] * 32 + 16 + (above[x+1] - above[x]) * shift) >> 5 - __m256i a0_x, a1_x, a0_y, a1_y, a32, a0_1_x, a1_1_x, a16; - __m256i diff, min_base_y256, c3f; - __m128i a0_x128, a1_x128, a0_1_x128, a1_1_x128; + __m256i a0_x, a1_x, a0_y, a1_y, a32, a16; + __m256i diff, min_base_y256, c3f, shifty; + __m128i a0_x128, a1_x128, a0_1_x128, a1_1_x128, a0_1_x, a1_1_x, shiftx; - a16 = _mm256_set1_epi32(16); - min_base_y256 = _mm256_set1_epi32(min_base_y); - c3f = _mm256_set1_epi32(0x3f); + a16 = _mm256_set1_epi16(16); + min_base_y256 = _mm256_set1_epi16(min_base_y); + c3f = _mm256_set1_epi16(0x3f); for (int r = 0; r < H; r++) { __m256i b, res, shift; - __m128i resx[2], resy[2]; + __m128i resx, resy; __m128i resxy; for (int j = 0; j < W; j += 16) { int y = r + 1; @@ -3557,7 +3863,9 @@ static void dr_prediction_z2_HxW_avx2(int H, int W, uint8_t *dst, if (base_min_diff < 0) base_min_diff = 0; } if (base_shift > 7) { - resx[0] = _mm_setzero_si128(); + a0_x = _mm256_setzero_si256(); + a1_x = _mm256_setzero_si256(); + shift = _mm256_setzero_si256(); } else { a0_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift + j)); a1_x128 = @@ -3565,39 +3873,24 @@ static void dr_prediction_z2_HxW_avx2(int H, int W, uint8_t *dst, a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)LoadMaskx[base_shift]); a1_x128 = _mm_shuffle_epi8(a1_x128, *(__m128i *)LoadMaskx[base_shift]); - a0_x = _mm256_cvtepu8_epi32(a0_x128); - a1_x = _mm256_cvtepu8_epi32(a1_x128); + a0_x = _mm256_cvtepu8_epi16(a0_x128); + a1_x = _mm256_cvtepu8_epi16(a1_x128); - shift = _mm256_srli_epi32( - _mm256_and_si256( - _mm256_setr_epi32( - ((0 + j) << 6) - y * dx, ((1 + j) << 6) - y * dx, - ((2 + j) << 6) - y * dx, ((3 + j) << 6) - y * dx, - ((4 + j) << 6) - y * dx, ((5 + j) << 6) - y * dx, - ((6 + j) << 6) - y * dx, ((7 + j) << 6) - y * dx), - c3f), - 1); - - diff = _mm256_sub_epi32(a1_x, a0_x); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_x, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - res = _mm256_packus_epi32( - res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); - resx[0] = _mm_packus_epi16(_mm256_castsi256_si128(res), - _mm256_castsi256_si128(res)); + shift = _mm256_castsi128_si256(_mm_srli_epi16( + _mm_and_si128(_mm_setr_epi16( + ((0 + j) << 6) - y * dx, ((1 + j) << 6) - y * dx, + ((2 + j) << 6) - y * dx, ((3 + j) << 6) - y * dx, + ((4 + j) << 6) - y * dx, ((5 + j) << 6) - y * dx, + ((6 + j) << 6) - y * dx, ((7 + j) << 6) - y * dx), + _mm256_castsi256_si128(c3f)), + 1)); } + base_shift = 0; if ((base_x + j + 8) < (min_base_x - 1)) { base_shift = (min_base_x - (base_x + j + 8) - 1); } - if (base_shift > 7) { - resx[1] = _mm_setzero_si128(); - } else { + if (base_shift <= 7) { a0_1_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 8 + j)); a1_1_x128 = @@ -3607,110 +3900,84 @@ static void dr_prediction_z2_HxW_avx2(int H, int W, uint8_t *dst, a1_1_x128 = _mm_shuffle_epi8(a1_1_x128, *(__m128i *)LoadMaskx[base_shift]); - a0_1_x = _mm256_cvtepu8_epi32(a0_1_x128); - a1_1_x = _mm256_cvtepu8_epi32(a1_1_x128); + a0_1_x = _mm_cvtepu8_epi16(a0_1_x128); + a1_1_x = _mm_cvtepu8_epi16(a1_1_x128); - shift = _mm256_srli_epi32( - _mm256_and_si256( - _mm256_setr_epi32( + shiftx = _mm_srli_epi16( + _mm_and_si128( + _mm_setr_epi16( ((8 + j) << 6) - y * dx, ((9 + j) << 6) - y * dx, ((10 + j) << 6) - y * dx, ((11 + j) << 6) - y * dx, ((12 + j) << 6) - y * dx, ((13 + j) << 6) - y * dx, ((14 + j) << 6) - y * dx, ((15 + j) << 6) - y * dx), - _mm256_set1_epi32(0x3f)), + _mm256_castsi256_si128(c3f)), 1); - diff = _mm256_sub_epi32(a1_1_x, a0_1_x); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_1_x, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - b = _mm256_mullo_epi32(diff, shift); - - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - res = _mm256_packus_epi32( - res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); - resx[1] = _mm_packus_epi16(_mm256_castsi256_si128(res), - _mm256_castsi256_si128(res)); + a0_x = _mm256_inserti128_si256(a0_x, a0_1_x, 1); + a1_x = _mm256_inserti128_si256(a1_x, a1_1_x, 1); + shift = _mm256_inserti128_si256(shift, shiftx, 1); } - resx[0] = _mm_unpacklo_epi64(resx[0], resx[1]); + + diff = _mm256_sub_epi16(a1_x, a0_x); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0_x, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 + + b = _mm256_mullo_epi16(diff, shift); + res = _mm256_add_epi16(a32, b); + res = _mm256_srli_epi16(res, 5); // 16 16-bit values + resx = _mm256_castsi256_si128(_mm256_packus_epi16( + res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1)))); // y calc if ((base_x < min_base_x)) { - DECLARE_ALIGNED(32, int, base_y_c[16]); - __m256i r6, c256, dy256, y_c256, y_c_1_256, base_y_c256, mask256; - r6 = _mm256_set1_epi32(r << 6); - dy256 = _mm256_set1_epi32(dy); - c256 = _mm256_setr_epi32(1 + j, 2 + j, 3 + j, 4 + j, 5 + j, 6 + j, - 7 + j, 8 + j); - y_c256 = _mm256_sub_epi32(r6, _mm256_mullo_epi32(c256, dy256)); - base_y_c256 = _mm256_srai_epi32(y_c256, frac_bits_y); - mask256 = _mm256_cmpgt_epi32(min_base_y256, base_y_c256); - base_y_c256 = _mm256_andnot_si256(mask256, base_y_c256); - _mm256_store_si256((__m256i *)base_y_c, base_y_c256); - c256 = _mm256_setr_epi32(9 + j, 10 + j, 11 + j, 12 + j, 13 + j, 14 + j, - 15 + j, 16 + j); - y_c_1_256 = _mm256_sub_epi32(r6, _mm256_mullo_epi32(c256, dy256)); - base_y_c256 = _mm256_srai_epi32(y_c_1_256, frac_bits_y); - mask256 = _mm256_cmpgt_epi32(min_base_y256, base_y_c256); - base_y_c256 = _mm256_andnot_si256(mask256, base_y_c256); - _mm256_store_si256((__m256i *)(base_y_c + 8), base_y_c256); + DECLARE_ALIGNED(32, int16_t, base_y_c[16]); + __m256i r6, c256, dy256, y_c256, base_y_c256, mask256, mul16; + r6 = _mm256_set1_epi16(r << 6); + dy256 = _mm256_set1_epi16(dy); + c256 = _mm256_setr_epi16(1 + j, 2 + j, 3 + j, 4 + j, 5 + j, 6 + j, + 7 + j, 8 + j, 9 + j, 10 + j, 11 + j, 12 + j, + 13 + j, 14 + j, 15 + j, 16 + j); + mul16 = _mm256_min_epu16(_mm256_mullo_epi16(c256, dy256), + _mm256_srli_epi16(min_base_y256, 1)); + y_c256 = _mm256_sub_epi16(r6, mul16); - a0_y = _mm256_cvtepu8_epi32(_mm_setr_epi8( + base_y_c256 = _mm256_srai_epi16(y_c256, frac_bits_y); + mask256 = _mm256_cmpgt_epi16(min_base_y256, base_y_c256); + base_y_c256 = _mm256_andnot_si256(mask256, base_y_c256); + _mm256_store_si256((__m256i *)base_y_c, base_y_c256); /**/ + + a0_y = _mm256_setr_epi16( left[base_y_c[0]], left[base_y_c[1]], left[base_y_c[2]], left[base_y_c[3]], left[base_y_c[4]], left[base_y_c[5]], - left[base_y_c[6]], left[base_y_c[7]], 0, 0, 0, 0, 0, 0, 0, 0)); - a1_y = _mm256_cvtepu8_epi32(_mm_setr_epi8( + left[base_y_c[6]], left[base_y_c[7]], left[base_y_c[8]], + left[base_y_c[9]], left[base_y_c[10]], left[base_y_c[11]], + left[base_y_c[12]], left[base_y_c[13]], left[base_y_c[14]], + left[base_y_c[15]]); + a1_y = _mm256_setr_epi16( left[base_y_c[0] + 1], left[base_y_c[1] + 1], left[base_y_c[2] + 1], left[base_y_c[3] + 1], left[base_y_c[4] + 1], left[base_y_c[5] + 1], - left[base_y_c[6] + 1], left[base_y_c[7] + 1], 0, 0, 0, 0, 0, 0, 0, - 0)); + left[base_y_c[6] + 1], left[base_y_c[7] + 1], left[base_y_c[8] + 1], + left[base_y_c[9] + 1], left[base_y_c[10] + 1], + left[base_y_c[11] + 1], left[base_y_c[12] + 1], + left[base_y_c[13] + 1], left[base_y_c[14] + 1], + left[base_y_c[15] + 1]); - shift = _mm256_srli_epi32(_mm256_and_si256(y_c256, c3f), 1); + shifty = _mm256_srli_epi16(_mm256_and_si256(y_c256, c3f), 1); - diff = _mm256_sub_epi32(a1_y, a0_y); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_y, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 + diff = _mm256_sub_epi16(a1_y, a0_y); // a[x+1] - a[x] + a32 = _mm256_slli_epi16(a0_y, 5); // a[x] * 32 + a32 = _mm256_add_epi16(a32, a16); // a[x] * 32 + 16 - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); + b = _mm256_mullo_epi16(diff, shifty); + res = _mm256_add_epi16(a32, b); + res = _mm256_srli_epi16(res, 5); // 16 16-bit values + resy = _mm256_castsi256_si128(_mm256_packus_epi16( + res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1)))); - res = _mm256_packus_epi32( - res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); - resy[0] = _mm_packus_epi16(_mm256_castsi256_si128(res), - _mm256_castsi256_si128(res)); - - a0_y = _mm256_cvtepu8_epi32(_mm_setr_epi8( - left[base_y_c[8]], left[base_y_c[9]], left[base_y_c[10]], - left[base_y_c[11]], left[base_y_c[12]], left[base_y_c[13]], - left[base_y_c[14]], left[base_y_c[15]], 0, 0, 0, 0, 0, 0, 0, 0)); - a1_y = _mm256_cvtepu8_epi32( - _mm_setr_epi8(left[base_y_c[8] + 1], left[base_y_c[9] + 1], - left[base_y_c[10] + 1], left[base_y_c[11] + 1], - left[base_y_c[12] + 1], left[base_y_c[13] + 1], - left[base_y_c[14] + 1], left[base_y_c[15] + 1], 0, 0, - 0, 0, 0, 0, 0, 0)); - shift = _mm256_srli_epi32(_mm256_and_si256(y_c_1_256, c3f), 1); - - diff = _mm256_sub_epi32(a1_y, a0_y); // a[x+1] - a[x] - a32 = _mm256_slli_epi32(a0_y, 5); // a[x] * 32 - a32 = _mm256_add_epi32(a32, a16); // a[x] * 32 + 16 - - b = _mm256_mullo_epi32(diff, shift); - res = _mm256_add_epi32(a32, b); - res = _mm256_srli_epi32(res, 5); - - res = _mm256_packus_epi32( - res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); - resy[1] = - _mm_packus_epi16(_mm256_castsi256_si128(res), - _mm256_castsi256_si128(res)); // 8 16bit values - resy[0] = _mm_unpacklo_epi64(resy[0], resy[1]); } else { - resy[0] = resx[0]; + resy = _mm_setzero_si128(); } - resxy = _mm_blendv_epi8(resx[0], resy[0], - *(__m128i *)BaseMask[base_min_diff]); + resxy = _mm_blendv_epi8(resx, resy, *(__m128i *)BaseMask[base_min_diff]); _mm_storeu_si128((__m128i *)(dst + j), resxy); } // for j dst += stride; @@ -3732,7 +3999,6 @@ void av1_dr_prediction_z2_avx2(uint8_t *dst, ptrdiff_t stride, int bw, int bh, case 8: dr_prediction_z2_Nx8_avx2(bh, dst, stride, above, left, upsample_above, upsample_left, dx, dy); - break; default: dr_prediction_z2_HxW_avx2(bh, bw, dst, stride, above, left, @@ -4370,5 +4636,4 @@ void av1_dr_prediction_z3_avx2(uint8_t *dst, ptrdiff_t stride, int bw, int bh, } } } - return; } diff --git a/third_party/aom/aom_dsp/x86/intrapred_sse2_asm.asm b/third_party/aom/aom_dsp/x86/intrapred_sse2_asm.asm deleted file mode 100644 index 9aece27beb..0000000000 --- a/third_party/aom/aom_dsp/x86/intrapred_sse2_asm.asm +++ /dev/null @@ -1,625 +0,0 @@ -; -; Copyright (c) 2016, 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/x86inc/x86inc.asm" - -SECTION_RODATA -pb_1: times 16 db 1 -pw_4: times 8 dw 4 -pw_8: times 8 dw 8 -pw_16: times 8 dw 16 -pw_32: times 8 dw 32 -dc_128: times 16 db 128 -pw2_4: times 8 dw 2 -pw2_8: times 8 dw 4 -pw2_16: times 8 dw 8 -pw2_32: times 8 dw 16 - -SECTION .text - -; ------------------------------------------ -; input: x, y, z, result -; -; trick from pascal -; (x+2y+z+2)>>2 can be calculated as: -; result = avg(x,z) -; result -= xor(x,z) & 1 -; result = avg(result,y) -; ------------------------------------------ -%macro X_PLUS_2Y_PLUS_Z_PLUS_2_RSH_2 4 - pavgb %4, %1, %3 - pxor %3, %1 - pand %3, [GLOBAL(pb_1)] - psubb %4, %3 - pavgb %4, %2 -%endmacro - -INIT_XMM sse2 -cglobal dc_predictor_4x4, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - movd m2, [leftq] - movd m0, [aboveq] - pxor m1, m1 - punpckldq m0, m2 - psadbw m0, m1 - paddw m0, [GLOBAL(pw_4)] - psraw m0, 3 - pshuflw m0, m0, 0x0 - packuswb m0, m0 - movd [dstq ], m0 - movd [dstq+strideq], m0 - lea dstq, [dstq+strideq*2] - movd [dstq ], m0 - movd [dstq+strideq], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_left_predictor_4x4, 2, 5, 2, dst, stride, above, left, goffset - movifnidn leftq, leftmp - GET_GOT goffsetq - - pxor m1, m1 - movd m0, [leftq] - psadbw m0, m1 - paddw m0, [GLOBAL(pw2_4)] - psraw m0, 2 - pshuflw m0, m0, 0x0 - packuswb m0, m0 - movd [dstq ], m0 - movd [dstq+strideq], m0 - lea dstq, [dstq+strideq*2] - movd [dstq ], m0 - movd [dstq+strideq], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_top_predictor_4x4, 3, 5, 2, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - movd m0, [aboveq] - psadbw m0, m1 - paddw m0, [GLOBAL(pw2_4)] - psraw m0, 2 - pshuflw m0, m0, 0x0 - packuswb m0, m0 - movd [dstq ], m0 - movd [dstq+strideq], m0 - lea dstq, [dstq+strideq*2] - movd [dstq ], m0 - movd [dstq+strideq], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_predictor_8x8, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - movq m0, [aboveq] - movq m2, [leftq] - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - psadbw m0, m1 - psadbw m2, m1 - paddw m0, m2 - paddw m0, [GLOBAL(pw_8)] - psraw m0, 4 - punpcklbw m0, m0 - pshuflw m0, m0, 0x0 - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_top_predictor_8x8, 3, 5, 2, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - movq m0, [aboveq] - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - psadbw m0, m1 - paddw m0, [GLOBAL(pw2_8)] - psraw m0, 3 - punpcklbw m0, m0 - pshuflw m0, m0, 0x0 - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_left_predictor_8x8, 2, 5, 2, dst, stride, above, left, goffset - movifnidn leftq, leftmp - GET_GOT goffsetq - - pxor m1, m1 - movq m0, [leftq] - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - psadbw m0, m1 - paddw m0, [GLOBAL(pw2_8)] - psraw m0, 3 - punpcklbw m0, m0 - pshuflw m0, m0, 0x0 - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_128_predictor_4x4, 2, 5, 1, dst, stride, above, left, goffset - GET_GOT goffsetq - - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - movd m0, [GLOBAL(dc_128)] - movd [dstq ], m0 - movd [dstq+strideq ], m0 - movd [dstq+strideq*2], m0 - movd [dstq+stride3q ], m0 - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_128_predictor_8x8, 2, 5, 1, dst, stride, above, left, goffset - GET_GOT goffsetq - - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - movq m0, [GLOBAL(dc_128)] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal dc_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [aboveq] - mova m2, [leftq] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 4 - psadbw m0, m1 - psadbw m2, m1 - paddw m0, m2 - movhlps m2, m0 - paddw m0, m2 - paddw m0, [GLOBAL(pw_16)] - psraw m0, 5 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - packuswb m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - - -INIT_XMM sse2 -cglobal dc_top_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [aboveq] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 4 - psadbw m0, m1 - movhlps m2, m0 - paddw m0, m2 - paddw m0, [GLOBAL(pw2_16)] - psraw m0, 4 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - packuswb m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal dc_left_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [leftq] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 4 - psadbw m0, m1 - movhlps m2, m0 - paddw m0, m2 - paddw m0, [GLOBAL(pw2_16)] - psraw m0, 4 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - packuswb m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal dc_128_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 4 - mova m0, [GLOBAL(dc_128)] -.loop: - mova [dstq ], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - RESTORE_GOT - RET - - -INIT_XMM sse2 -cglobal dc_predictor_32x32, 4, 5, 5, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [aboveq] - mova m2, [aboveq+16] - mova m3, [leftq] - mova m4, [leftq+16] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 8 - psadbw m0, m1 - psadbw m2, m1 - psadbw m3, m1 - psadbw m4, m1 - paddw m0, m2 - paddw m0, m3 - paddw m0, m4 - movhlps m2, m0 - paddw m0, m2 - paddw m0, [GLOBAL(pw_32)] - psraw m0, 6 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - packuswb m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq +16], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq +16], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2+16], m0 - mova [dstq+stride3q ], m0 - mova [dstq+stride3q +16], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal dc_top_predictor_32x32, 4, 5, 5, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [aboveq] - mova m2, [aboveq+16] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 8 - psadbw m0, m1 - psadbw m2, m1 - paddw m0, m2 - movhlps m2, m0 - paddw m0, m2 - paddw m0, [GLOBAL(pw2_32)] - psraw m0, 5 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - packuswb m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq +16], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq +16], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2+16], m0 - mova [dstq+stride3q ], m0 - mova [dstq+stride3q +16], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal dc_left_predictor_32x32, 4, 5, 5, dst, stride, above, left, goffset - GET_GOT goffsetq - - pxor m1, m1 - mova m0, [leftq] - mova m2, [leftq+16] - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 8 - psadbw m0, m1 - psadbw m2, m1 - paddw m0, m2 - movhlps m2, m0 - paddw m0, m2 - paddw m0, [GLOBAL(pw2_32)] - psraw m0, 5 - pshuflw m0, m0, 0x0 - punpcklqdq m0, m0 - packuswb m0, m0 -.loop: - mova [dstq ], m0 - mova [dstq +16], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq +16], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2+16], m0 - mova [dstq+stride3q ], m0 - mova [dstq+stride3q +16], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - - RESTORE_GOT - REP_RET - -INIT_XMM sse2 -cglobal dc_128_predictor_32x32, 4, 5, 3, dst, stride, above, left, goffset - GET_GOT goffsetq - - DEFINE_ARGS dst, stride, stride3, lines4 - lea stride3q, [strideq*3] - mov lines4d, 8 - mova m0, [GLOBAL(dc_128)] -.loop: - mova [dstq ], m0 - mova [dstq +16], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq +16], m0 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2+16], m0 - mova [dstq+stride3q ], m0 - mova [dstq+stride3q +16], m0 - lea dstq, [dstq+strideq*4] - dec lines4d - jnz .loop - RESTORE_GOT - RET - -INIT_XMM sse2 -cglobal v_predictor_4x4, 3, 3, 1, dst, stride, above - movd m0, [aboveq] - movd [dstq ], m0 - movd [dstq+strideq], m0 - lea dstq, [dstq+strideq*2] - movd [dstq ], m0 - movd [dstq+strideq], m0 - RET - -INIT_XMM sse2 -cglobal v_predictor_8x8, 3, 3, 1, dst, stride, above - movq m0, [aboveq] - DEFINE_ARGS dst, stride, stride3 - lea stride3q, [strideq*3] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - movq [dstq ], m0 - movq [dstq+strideq ], m0 - movq [dstq+strideq*2], m0 - movq [dstq+stride3q ], m0 - RET - -INIT_XMM sse2 -cglobal v_predictor_16x16, 3, 4, 1, dst, stride, above - mova m0, [aboveq] - DEFINE_ARGS dst, stride, stride3, nlines4 - lea stride3q, [strideq*3] - mov nlines4d, 4 -.loop: - mova [dstq ], m0 - mova [dstq+strideq ], m0 - mova [dstq+strideq*2], m0 - mova [dstq+stride3q ], m0 - lea dstq, [dstq+strideq*4] - dec nlines4d - jnz .loop - REP_RET - -INIT_XMM sse2 -cglobal v_predictor_32x32, 3, 4, 2, dst, stride, above - mova m0, [aboveq] - mova m1, [aboveq+16] - DEFINE_ARGS dst, stride, stride3, nlines4 - lea stride3q, [strideq*3] - mov nlines4d, 8 -.loop: - mova [dstq ], m0 - mova [dstq +16], m1 - mova [dstq+strideq ], m0 - mova [dstq+strideq +16], m1 - mova [dstq+strideq*2 ], m0 - mova [dstq+strideq*2+16], m1 - mova [dstq+stride3q ], m0 - mova [dstq+stride3q +16], m1 - lea dstq, [dstq+strideq*4] - dec nlines4d - jnz .loop - REP_RET - -INIT_XMM sse2 -cglobal h_predictor_4x4, 2, 4, 4, dst, stride, line, left - movifnidn leftq, leftmp - movd m0, [leftq] - punpcklbw m0, m0 - punpcklbw m0, m0 - pshufd m1, m0, 0x1 - movd [dstq ], m0 - movd [dstq+strideq], m1 - pshufd m2, m0, 0x2 - lea dstq, [dstq+strideq*2] - pshufd m3, m0, 0x3 - movd [dstq ], m2 - movd [dstq+strideq], m3 - RET - -INIT_XMM sse2 -cglobal h_predictor_8x8, 2, 5, 3, dst, stride, line, left - movifnidn leftq, leftmp - mov lineq, -2 - DEFINE_ARGS dst, stride, line, left, stride3 - lea stride3q, [strideq*3] - movq m0, [leftq ] - punpcklbw m0, m0 ; l1 l1 l2 l2 ... l8 l8 -.loop: - pshuflw m1, m0, 0x0 ; l1 l1 l1 l1 l1 l1 l1 l1 - pshuflw m2, m0, 0x55 ; l2 l2 l2 l2 l2 l2 l2 l2 - movq [dstq ], m1 - movq [dstq+strideq], m2 - pshuflw m1, m0, 0xaa - pshuflw m2, m0, 0xff - movq [dstq+strideq*2], m1 - movq [dstq+stride3q ], m2 - pshufd m0, m0, 0xe ; [63:0] l5 l5 l6 l6 l7 l7 l8 l8 - inc lineq - lea dstq, [dstq+strideq*4] - jnz .loop - REP_RET - -INIT_XMM sse2 -cglobal h_predictor_16x16, 2, 5, 3, dst, stride, line, left - movifnidn leftq, leftmp - mov lineq, -4 - DEFINE_ARGS dst, stride, line, left, stride3 - lea stride3q, [strideq*3] -.loop: - movd m0, [leftq] - punpcklbw m0, m0 - punpcklbw m0, m0 ; l1 to l4 each repeated 4 times - pshufd m1, m0, 0x0 ; l1 repeated 16 times - pshufd m2, m0, 0x55 ; l2 repeated 16 times - mova [dstq ], m1 - mova [dstq+strideq ], m2 - pshufd m1, m0, 0xaa - pshufd m2, m0, 0xff - mova [dstq+strideq*2], m1 - mova [dstq+stride3q ], m2 - inc lineq - lea leftq, [leftq+4 ] - lea dstq, [dstq+strideq*4] - jnz .loop - REP_RET - -INIT_XMM sse2 -cglobal h_predictor_32x32, 2, 5, 3, dst, stride, line, left - movifnidn leftq, leftmp - mov lineq, -8 - DEFINE_ARGS dst, stride, line, left, stride3 - lea stride3q, [strideq*3] -.loop: - movd m0, [leftq] - punpcklbw m0, m0 - punpcklbw m0, m0 ; l1 to l4 each repeated 4 times - pshufd m1, m0, 0x0 ; l1 repeated 16 times - pshufd m2, m0, 0x55 ; l2 repeated 16 times - mova [dstq ], m1 - mova [dstq+16 ], m1 - mova [dstq+strideq ], m2 - mova [dstq+strideq+16 ], m2 - pshufd m1, m0, 0xaa - pshufd m2, m0, 0xff - mova [dstq+strideq*2 ], m1 - mova [dstq+strideq*2+16], m1 - mova [dstq+stride3q ], m2 - mova [dstq+stride3q+16 ], m2 - inc lineq - lea leftq, [leftq+4 ] - lea dstq, [dstq+strideq*4] - jnz .loop - REP_RET diff --git a/third_party/aom/aom_dsp/x86/loopfilter_sse2.c b/third_party/aom/aom_dsp/x86/loopfilter_sse2.c index e1981e555a..c021f500d2 100644 --- a/third_party/aom/aom_dsp/x86/loopfilter_sse2.c +++ b/third_party/aom/aom_dsp/x86/loopfilter_sse2.c @@ -23,8 +23,8 @@ static INLINE __m128i abs_diff(__m128i a, __m128i b) { } // this function treats its input as 2 parallel 8x4 matrices, transposes each of -// them to 4x8 independently while flipping the second matrix horizontaly. Used -// for 14 taps pq pairs creation +// them to 4x8 independently while flipping the second matrix horizontally. +// Used for 14 taps pq pairs creation static INLINE void transpose_pq_14_sse2(__m128i *x0, __m128i *x1, __m128i *x2, __m128i *x3, __m128i *q0p0, __m128i *q1p1, __m128i *q2p2, diff --git a/third_party/aom/aom_dsp/x86/quantize_x86.h b/third_party/aom/aom_dsp/x86/quantize_x86.h index 3b94bb05e3..b2de01bf27 100644 --- a/third_party/aom/aom_dsp/x86/quantize_x86.h +++ b/third_party/aom/aom_dsp/x86/quantize_x86.h @@ -32,6 +32,11 @@ static INLINE __m128i invert_sign_sse2(__m128i a, __m128i sign) { return _mm_sub_epi16(a, sign); } +static INLINE __m128i invert_sign_32_sse2(__m128i a, __m128i sign) { + a = _mm_xor_si128(a, sign); + return _mm_sub_epi32(a, sign); +} + static INLINE void calculate_qcoeff(__m128i *coeff, const __m128i round, const __m128i quant, const __m128i shift) { __m128i tmp, qcoeff; @@ -41,10 +46,53 @@ static INLINE void calculate_qcoeff(__m128i *coeff, const __m128i round, *coeff = _mm_mulhi_epi16(qcoeff, shift); } +static INLINE void calculate_qcoeff_log_scale(__m128i *coeff, + const __m128i round, + const __m128i quant, + const __m128i *shift, + const int *log_scale) { + __m128i tmp, tmp1, qcoeff; + qcoeff = _mm_adds_epi16(*coeff, round); + tmp = _mm_mulhi_epi16(qcoeff, quant); + qcoeff = _mm_add_epi16(tmp, qcoeff); + tmp = _mm_mullo_epi16(qcoeff, *shift); + tmp = _mm_srli_epi16(tmp, (16 - *log_scale)); + tmp1 = _mm_mulhi_epi16(qcoeff, *shift); + tmp1 = _mm_slli_epi16(tmp1, *log_scale); + *coeff = _mm_or_si128(tmp, tmp1); +} + static INLINE __m128i calculate_dqcoeff(__m128i qcoeff, __m128i dequant) { return _mm_mullo_epi16(qcoeff, dequant); } +static INLINE void calculate_dqcoeff_and_store_log_scale(__m128i qcoeff, + __m128i dequant, + const __m128i zero, + tran_low_t *dqcoeff, + const int *log_scale) { + // calculate abs + __m128i coeff_sign = _mm_srai_epi16(qcoeff, 15); + __m128i coeff = invert_sign_sse2(qcoeff, coeff_sign); + + const __m128i sign_0 = _mm_unpacklo_epi16(coeff_sign, zero); + const __m128i sign_1 = _mm_unpackhi_epi16(coeff_sign, zero); + + const __m128i low = _mm_mullo_epi16(coeff, dequant); + const __m128i high = _mm_mulhi_epi16(coeff, dequant); + __m128i dqcoeff32_0 = _mm_unpacklo_epi16(low, high); + __m128i dqcoeff32_1 = _mm_unpackhi_epi16(low, high); + + dqcoeff32_0 = _mm_srli_epi32(dqcoeff32_0, *log_scale); + dqcoeff32_1 = _mm_srli_epi32(dqcoeff32_1, *log_scale); + + dqcoeff32_0 = invert_sign_32_sse2(dqcoeff32_0, sign_0); + dqcoeff32_1 = invert_sign_32_sse2(dqcoeff32_1, sign_1); + + _mm_store_si128((__m128i *)(dqcoeff), dqcoeff32_0); + _mm_store_si128((__m128i *)(dqcoeff + 4), dqcoeff32_1); +} + // Scan 16 values for eob reference in scan_ptr. Use masks (-1) from comparing // to zbin to add 1 to the index in 'scan'. static INLINE __m128i scan_for_eob(__m128i *coeff0, __m128i *coeff1, diff --git a/third_party/aom/aom_dsp/x86/ssim_opt_x86_64.asm b/third_party/aom/aom_dsp/x86/ssim_opt_x86_64.asm deleted file mode 100644 index 6d9b5a12f1..0000000000 --- a/third_party/aom/aom_dsp/x86/ssim_opt_x86_64.asm +++ /dev/null @@ -1,222 +0,0 @@ -; -; Copyright (c) 2016, 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 "aom_ports/x86_abi_support.asm" - -; tabulate_ssim - sums sum_s,sum_r,sum_sq_s,sum_sq_r, sum_sxr -%macro TABULATE_SSIM 0 - paddusw xmm15, xmm3 ; sum_s - paddusw xmm14, xmm4 ; sum_r - movdqa xmm1, xmm3 - pmaddwd xmm1, xmm1 - paddd xmm13, xmm1 ; sum_sq_s - movdqa xmm2, xmm4 - pmaddwd xmm2, xmm2 - paddd xmm12, xmm2 ; sum_sq_r - pmaddwd xmm3, xmm4 - paddd xmm11, xmm3 ; sum_sxr -%endmacro - -; Sum across the register %1 starting with q words -%macro SUM_ACROSS_Q 1 - movdqa xmm2,%1 - punpckldq %1,xmm0 - punpckhdq xmm2,xmm0 - paddq %1,xmm2 - movdqa xmm2,%1 - punpcklqdq %1,xmm0 - punpckhqdq xmm2,xmm0 - paddq %1,xmm2 -%endmacro - -; Sum across the register %1 starting with q words -%macro SUM_ACROSS_W 1 - movdqa xmm1, %1 - punpcklwd %1,xmm0 - punpckhwd xmm1,xmm0 - paddd %1, xmm1 - SUM_ACROSS_Q %1 -%endmacro - -SECTION .text - -;void ssim_parms_sse2( -; unsigned char *s, -; int sp, -; unsigned char *r, -; int rp -; uint32_t *sum_s, -; uint32_t *sum_r, -; uint32_t *sum_sq_s, -; uint32_t *sum_sq_r, -; uint32_t *sum_sxr); -; -; TODO: Use parm passing through structure, probably don't need the pxors -; ( calling app will initialize to 0 ) could easily fit everything in sse2 -; without too much hastle, and can probably do better estimates with psadw -; or pavgb At this point this is just meant to be first pass for calculating -; all the parms needed for 16x16 ssim so we can play with dssim as distortion -; in mode selection code. -global sym(aom_ssim_parms_16x16_sse2) PRIVATE -sym(aom_ssim_parms_16x16_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 9 - SAVE_XMM 15 - push rsi - push rdi - ; end prolog - - mov rsi, arg(0) ;s - mov rcx, arg(1) ;sp - mov rdi, arg(2) ;r - mov rax, arg(3) ;rp - - pxor xmm0, xmm0 - pxor xmm15,xmm15 ;sum_s - pxor xmm14,xmm14 ;sum_r - pxor xmm13,xmm13 ;sum_sq_s - pxor xmm12,xmm12 ;sum_sq_r - pxor xmm11,xmm11 ;sum_sxr - - mov rdx, 16 ;row counter -.NextRow: - - ;grab source and reference pixels - movdqu xmm5, [rsi] - movdqu xmm6, [rdi] - movdqa xmm3, xmm5 - movdqa xmm4, xmm6 - punpckhbw xmm3, xmm0 ; high_s - punpckhbw xmm4, xmm0 ; high_r - - TABULATE_SSIM - - movdqa xmm3, xmm5 - movdqa xmm4, xmm6 - punpcklbw xmm3, xmm0 ; low_s - punpcklbw xmm4, xmm0 ; low_r - - TABULATE_SSIM - - add rsi, rcx ; next s row - add rdi, rax ; next r row - - dec rdx ; counter - jnz .NextRow - - SUM_ACROSS_W xmm15 - SUM_ACROSS_W xmm14 - SUM_ACROSS_Q xmm13 - SUM_ACROSS_Q xmm12 - SUM_ACROSS_Q xmm11 - - mov rdi,arg(4) - movd [rdi], xmm15; - mov rdi,arg(5) - movd [rdi], xmm14; - mov rdi,arg(6) - movd [rdi], xmm13; - mov rdi,arg(7) - movd [rdi], xmm12; - mov rdi,arg(8) - movd [rdi], xmm11; - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -;void ssim_parms_sse2( -; unsigned char *s, -; int sp, -; unsigned char *r, -; int rp -; uint32_t *sum_s, -; uint32_t *sum_r, -; uint32_t *sum_sq_s, -; uint32_t *sum_sq_r, -; uint32_t *sum_sxr); -; -; TODO: Use parm passing through structure, probably don't need the pxors -; ( calling app will initialize to 0 ) could easily fit everything in sse2 -; without too much hastle, and can probably do better estimates with psadw -; or pavgb At this point this is just meant to be first pass for calculating -; all the parms needed for 16x16 ssim so we can play with dssim as distortion -; in mode selection code. -global sym(aom_ssim_parms_8x8_sse2) PRIVATE -sym(aom_ssim_parms_8x8_sse2): - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 9 - SAVE_XMM 15 - push rsi - push rdi - ; end prolog - - mov rsi, arg(0) ;s - mov rcx, arg(1) ;sp - mov rdi, arg(2) ;r - mov rax, arg(3) ;rp - - pxor xmm0, xmm0 - pxor xmm15,xmm15 ;sum_s - pxor xmm14,xmm14 ;sum_r - pxor xmm13,xmm13 ;sum_sq_s - pxor xmm12,xmm12 ;sum_sq_r - pxor xmm11,xmm11 ;sum_sxr - - mov rdx, 8 ;row counter -.NextRow: - - ;grab source and reference pixels - movq xmm3, [rsi] - movq xmm4, [rdi] - punpcklbw xmm3, xmm0 ; low_s - punpcklbw xmm4, xmm0 ; low_r - - TABULATE_SSIM - - add rsi, rcx ; next s row - add rdi, rax ; next r row - - dec rdx ; counter - jnz .NextRow - - SUM_ACROSS_W xmm15 - SUM_ACROSS_W xmm14 - SUM_ACROSS_Q xmm13 - SUM_ACROSS_Q xmm12 - SUM_ACROSS_Q xmm11 - - mov rdi,arg(4) - movd [rdi], xmm15; - mov rdi,arg(5) - movd [rdi], xmm14; - mov rdi,arg(6) - movd [rdi], xmm13; - mov rdi,arg(7) - movd [rdi], xmm12; - mov rdi,arg(8) - movd [rdi], xmm11; - - ; begin epilog - pop rdi - pop rsi - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret diff --git a/third_party/aom/aom_dsp/x86/txfm_common_avx2.h b/third_party/aom/aom_dsp/x86/txfm_common_avx2.h index 8a40508986..06a77e75a5 100644 --- a/third_party/aom/aom_dsp/x86/txfm_common_avx2.h +++ b/third_party/aom/aom_dsp/x86/txfm_common_avx2.h @@ -168,6 +168,36 @@ static INLINE void transpose_16bit_16x16_avx2(const __m256i *const in, out[7 + 8] = _mm256_permute2x128_si256(c[12 + 2], c[13 + 2], 0x31); } +static INLINE void transpose_16bit_16x8_avx2(const __m256i *const in, + __m256i *const out) { + const __m256i a0 = _mm256_unpacklo_epi16(in[0], in[1]); + const __m256i a1 = _mm256_unpacklo_epi16(in[2], in[3]); + const __m256i a2 = _mm256_unpacklo_epi16(in[4], in[5]); + const __m256i a3 = _mm256_unpacklo_epi16(in[6], in[7]); + const __m256i a4 = _mm256_unpackhi_epi16(in[0], in[1]); + const __m256i a5 = _mm256_unpackhi_epi16(in[2], in[3]); + const __m256i a6 = _mm256_unpackhi_epi16(in[4], in[5]); + const __m256i a7 = _mm256_unpackhi_epi16(in[6], in[7]); + + const __m256i b0 = _mm256_unpacklo_epi32(a0, a1); + const __m256i b1 = _mm256_unpacklo_epi32(a2, a3); + const __m256i b2 = _mm256_unpacklo_epi32(a4, a5); + const __m256i b3 = _mm256_unpacklo_epi32(a6, a7); + const __m256i b4 = _mm256_unpackhi_epi32(a0, a1); + const __m256i b5 = _mm256_unpackhi_epi32(a2, a3); + const __m256i b6 = _mm256_unpackhi_epi32(a4, a5); + const __m256i b7 = _mm256_unpackhi_epi32(a6, a7); + + out[0] = _mm256_unpacklo_epi64(b0, b1); + out[1] = _mm256_unpackhi_epi64(b0, b1); + out[2] = _mm256_unpacklo_epi64(b4, b5); + out[3] = _mm256_unpackhi_epi64(b4, b5); + out[4] = _mm256_unpacklo_epi64(b2, b3); + out[5] = _mm256_unpackhi_epi64(b2, b3); + out[6] = _mm256_unpacklo_epi64(b6, b7); + out[7] = _mm256_unpackhi_epi64(b6, b7); +} + static INLINE void flip_buf_avx2(__m256i *in, __m256i *out, int size) { for (int i = 0; i < size; ++i) { out[size - i - 1] = in[i]; @@ -236,6 +266,66 @@ static INLINE void av1_round_shift_rect_array_32_avx2(__m256i *input, } } +static INLINE __m256i scale_round_avx2(const __m256i a, const int scale) { + const __m256i scale_rounding = + pair_set_w16_epi16(scale, 1 << (NewSqrt2Bits - 1)); + const __m256i b = _mm256_madd_epi16(a, scale_rounding); + return _mm256_srai_epi32(b, NewSqrt2Bits); +} + +static INLINE void store_rect_16bit_to_32bit_w8_avx2(const __m256i a, + int32_t *const b) { + const __m256i one = _mm256_set1_epi16(1); + const __m256i a_lo = _mm256_unpacklo_epi16(a, one); + const __m256i a_hi = _mm256_unpackhi_epi16(a, one); + const __m256i b_lo = scale_round_avx2(a_lo, NewSqrt2); + const __m256i b_hi = scale_round_avx2(a_hi, NewSqrt2); + const __m256i temp = _mm256_permute2f128_si256(b_lo, b_hi, 0x31); + _mm_store_si128((__m128i *)b, _mm256_castsi256_si128(b_lo)); + _mm_store_si128((__m128i *)(b + 4), _mm256_castsi256_si128(b_hi)); + _mm256_store_si256((__m256i *)(b + 64), temp); +} + +static INLINE void store_rect_buffer_16bit_to_32bit_w8_avx2( + const __m256i *const in, int32_t *const out, const int stride, + const int out_size) { + for (int i = 0; i < out_size; ++i) { + store_rect_16bit_to_32bit_w8_avx2(in[i], out + i * stride); + } +} + +static INLINE void pack_reg(const __m128i *in1, const __m128i *in2, + __m256i *out) { + out[0] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[0]), in2[0], 0x1); + out[1] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[1]), in2[1], 0x1); + out[2] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[2]), in2[2], 0x1); + out[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[3]), in2[3], 0x1); + out[4] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[4]), in2[4], 0x1); + out[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[5]), in2[5], 0x1); + out[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[6]), in2[6], 0x1); + out[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[7]), in2[7], 0x1); +} + +static INLINE void extract_reg(const __m256i *in, __m128i *out1) { + out1[0] = _mm256_castsi256_si128(in[0]); + out1[1] = _mm256_castsi256_si128(in[1]); + out1[2] = _mm256_castsi256_si128(in[2]); + out1[3] = _mm256_castsi256_si128(in[3]); + out1[4] = _mm256_castsi256_si128(in[4]); + out1[5] = _mm256_castsi256_si128(in[5]); + out1[6] = _mm256_castsi256_si128(in[6]); + out1[7] = _mm256_castsi256_si128(in[7]); + + out1[8] = _mm256_extracti128_si256(in[0], 0x01); + out1[9] = _mm256_extracti128_si256(in[1], 0x01); + out1[10] = _mm256_extracti128_si256(in[2], 0x01); + out1[11] = _mm256_extracti128_si256(in[3], 0x01); + out1[12] = _mm256_extracti128_si256(in[4], 0x01); + out1[13] = _mm256_extracti128_si256(in[5], 0x01); + out1[14] = _mm256_extracti128_si256(in[6], 0x01); + out1[15] = _mm256_extracti128_si256(in[7], 0x01); +} + #ifdef __cplusplus } #endif diff --git a/third_party/aom/aom_scale/aom_scale.cmake b/third_party/aom/aom_scale/aom_scale.cmake index 197dea6bd2..31997333ea 100644 --- a/third_party/aom/aom_scale/aom_scale.cmake +++ b/third_party/aom/aom_scale/aom_scale.cmake @@ -34,5 +34,9 @@ function(setup_aom_scale_targets) "AOM_SCALE_INTRIN_DSPR2" "aom") endif() + target_sources(aom PRIVATE $) + + # Pass the new lib targets up to the parent scope instance of + # $AOM_LIB_TARGETS. set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_scale PARENT_SCOPE) endfunction() diff --git a/third_party/aom/aom_scale/aom_scale_rtcd.pl b/third_party/aom/aom_scale/aom_scale_rtcd.pl index 27378c7ef4..eef6f16a74 100644 --- a/third_party/aom/aom_scale/aom_scale_rtcd.pl +++ b/third_party/aom/aom_scale/aom_scale_rtcd.pl @@ -26,6 +26,8 @@ if (aom_config("CONFIG_SPATIAL_RESAMPLING") eq "yes") { add_proto qw/void aom_vertical_band_2_1_scale_i/, "unsigned char *source, int src_pitch, unsigned char *dest, int dest_pitch, unsigned int dest_width"; } +add_proto qw/int aom_yv12_realloc_with_new_border/, "struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes"; + add_proto qw/void aom_yv12_extend_frame_borders/, "struct yv12_buffer_config *ybf, const int num_planes"; add_proto qw/void aom_yv12_copy_frame/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc, const int num_planes"; diff --git a/third_party/aom/aom_scale/generic/yv12config.c b/third_party/aom/aom_scale/generic/yv12config.c index dafe02b171..a5ad1a7963 100644 --- a/third_party/aom/aom_scale/generic/yv12config.c +++ b/third_party/aom/aom_scale/generic/yv12config.c @@ -46,37 +46,16 @@ int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { return 0; } -int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, - int ss_x, int ss_y, int use_highbitdepth, - int border, int byte_alignment, - aom_codec_frame_buffer_t *fb, - aom_get_frame_buffer_cb_fn_t cb, void *cb_priv) { -#if CONFIG_SIZE_LIMIT - if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1; -#endif - - /* Only support allocating buffers that have a border that's a multiple - * of 32. The border restriction is required to get 16-byte alignment of - * the start of the chroma rows without introducing an arbitrary gap - * between planes, which would break the semantics of things like - * aom_img_set_rect(). */ - if (border & 0x1f) return -3; - +static int realloc_frame_buffer_aligned( + YV12_BUFFER_CONFIG *ybf, int width, int height, int ss_x, int ss_y, + int use_highbitdepth, int border, int byte_alignment, + aom_codec_frame_buffer_t *fb, aom_get_frame_buffer_cb_fn_t cb, + void *cb_priv, const int y_stride, const uint64_t yplane_size, + const uint64_t uvplane_size, const int aligned_width, + const int aligned_height, const int uv_width, const int uv_height, + const int uv_stride, const int uv_border_w, const int uv_border_h) { if (ybf) { const int aom_byte_align = (byte_alignment == 0) ? 1 : byte_alignment; - const int aligned_width = (width + 7) & ~7; - const int aligned_height = (height + 7) & ~7; - const int y_stride = ((aligned_width + 2 * border) + 31) & ~31; - const uint64_t yplane_size = - (aligned_height + 2 * border) * (uint64_t)y_stride + byte_alignment; - const int uv_width = aligned_width >> ss_x; - const int uv_height = aligned_height >> ss_y; - const int uv_stride = y_stride >> ss_x; - const int uv_border_w = border >> ss_x; - const int uv_border_h = border >> ss_y; - const uint64_t uvplane_size = - (uv_height + 2 * uv_border_h) * (uint64_t)uv_stride + byte_alignment; - const uint64_t frame_size = (1 + use_highbitdepth) * (yplane_size + 2 * uvplane_size); @@ -191,6 +170,111 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, return -2; } +static int calc_stride_and_planesize(const int ss_x, const int ss_y, + const int aligned_width, + const int aligned_height, const int border, + const int byte_alignment, int *y_stride, + int *uv_stride, uint64_t *yplane_size, + uint64_t *uvplane_size, + const int uv_height) { + /* Only support allocating buffers that have a border that's a multiple + * of 32. The border restriction is required to get 16-byte alignment of + * the start of the chroma rows without introducing an arbitrary gap + * between planes, which would break the semantics of things like + * aom_img_set_rect(). */ + if (border & 0x1f) return -3; + *y_stride = ((aligned_width + 2 * border) + 31) & ~31; + *yplane_size = + (aligned_height + 2 * border) * (uint64_t)(*y_stride) + byte_alignment; + + *uv_stride = *y_stride >> ss_x; + *uvplane_size = (uv_height + 2 * (border >> ss_y)) * (uint64_t)(*uv_stride) + + byte_alignment; + return 0; +} + +int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, + int ss_x, int ss_y, int use_highbitdepth, + int border, int byte_alignment, + aom_codec_frame_buffer_t *fb, + aom_get_frame_buffer_cb_fn_t cb, void *cb_priv) { +#if CONFIG_SIZE_LIMIT + if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1; +#endif + + if (ybf) { + int y_stride = 0; + int uv_stride = 0; + uint64_t yplane_size = 0; + uint64_t uvplane_size = 0; + const int aligned_width = (width + 7) & ~7; + const int aligned_height = (height + 7) & ~7; + const int uv_width = aligned_width >> ss_x; + const int uv_height = aligned_height >> ss_y; + const int uv_border_w = border >> ss_x; + const int uv_border_h = border >> ss_y; + + int error = calc_stride_and_planesize( + ss_x, ss_y, aligned_width, aligned_height, border, byte_alignment, + &y_stride, &uv_stride, &yplane_size, &uvplane_size, uv_height); + if (error) return error; + return realloc_frame_buffer_aligned( + ybf, width, height, ss_x, ss_y, use_highbitdepth, border, + byte_alignment, fb, cb, cb_priv, y_stride, yplane_size, uvplane_size, + aligned_width, aligned_height, uv_width, uv_height, uv_stride, + uv_border_w, uv_border_h); + } + return -2; +} + +// TODO(anyone): This function allocates memory for +// lookahead buffer considering height and width is +// aligned to 128. Currently variance calculation of +// simple_motion_search_get_best_ref() function is done +// for full sb size (i.e integral multiple of max sb +// size = 128 or 64). Hence partial sbs need up to 127 +// pixels beyond frame boundary. 128 aligned limitation of +// lookahead buffer can be removed if variance calculation +// is adjusted for partial sbs + +// NOTE: Chroma width and height need not be aligned to +// 128 since variance calculation happens only for luma plane +int aom_realloc_lookahead_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, + int ss_x, int ss_y, int use_highbitdepth, + int border, int byte_alignment, + aom_codec_frame_buffer_t *fb, + aom_get_frame_buffer_cb_fn_t cb, + void *cb_priv) { + if (ybf) { + int y_stride = 0; + int uv_stride = 0; + uint64_t yplane_size = 0; + uint64_t uvplane_size = 0; + const int aligned_128_width = (width + 127) & ~127; + const int aligned_128_height = (height + 127) & ~127; + const int aligned_width = (width + 7) & ~7; + const int aligned_height = (height + 7) & ~7; + const int uv_64_height = aligned_128_height >> ss_y; + const int uv_width = aligned_width >> ss_x; + const int uv_height = aligned_height >> ss_y; + const int uv_border_w = border >> ss_x; + const int uv_border_h = border >> ss_y; + + int error = calc_stride_and_planesize( + ss_x, ss_y, aligned_128_width, aligned_128_height, border, + byte_alignment, &y_stride, &uv_stride, &yplane_size, &uvplane_size, + uv_64_height); + if (error) return error; + + return realloc_frame_buffer_aligned( + ybf, width, height, ss_x, ss_y, use_highbitdepth, border, + byte_alignment, fb, cb, cb_priv, y_stride, yplane_size, uvplane_size, + aligned_width, aligned_height, uv_width, uv_height, uv_stride, + uv_border_w, uv_border_h); + } + return -2; +} + int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int ss_x, int ss_y, int use_highbitdepth, int border, int byte_alignment) { diff --git a/third_party/aom/aom_scale/generic/yv12extend.c b/third_party/aom/aom_scale/generic/yv12extend.c index 127ca23116..6e9cfffed9 100644 --- a/third_party/aom/aom_scale/generic/yv12extend.c +++ b/third_party/aom/aom_scale/generic/yv12extend.c @@ -434,3 +434,28 @@ void aom_yv12_partial_coloc_copy_v_c(const YV12_BUFFER_CONFIG *src_bc, aom_yv12_partial_copy_v_c(src_bc, hstart, hend, vstart, vend, dst_bc, hstart, vstart); } + +int aom_yv12_realloc_with_new_border_c(YV12_BUFFER_CONFIG *ybf, int new_border, + int byte_alignment, int num_planes) { + if (ybf) { + if (new_border == ybf->border) return 0; + YV12_BUFFER_CONFIG new_buf; + memset(&new_buf, 0, sizeof(new_buf)); + const int error = aom_alloc_frame_buffer( + &new_buf, ybf->y_crop_width, ybf->y_crop_height, ybf->subsampling_x, + ybf->subsampling_y, ybf->flags & YV12_FLAG_HIGHBITDEPTH, new_border, + byte_alignment); + if (error) return error; + // Copy image buffer + aom_yv12_copy_frame(ybf, &new_buf, num_planes); + + // Extend up to new border + aom_extend_frame_borders(&new_buf, num_planes); + + // Now free the old buffer and replace with the new + aom_free_frame_buffer(ybf); + memcpy(ybf, &new_buf, sizeof(new_buf)); + return 0; + } + return -2; +} diff --git a/third_party/aom/aom_scale/yv12config.h b/third_party/aom/aom_scale/yv12config.h index bb0d56430b..04a1c04352 100644 --- a/third_party/aom/aom_scale/yv12config.h +++ b/third_party/aom/aom_scale/yv12config.h @@ -26,6 +26,7 @@ extern "C" { #define AOM_INTERP_EXTEND 4 #define AOM_BORDER_IN_PIXELS 288 #define AOM_ENC_NO_SCALE_BORDER 160 +#define AOM_ENC_LOOKAHEAD_BORDER 64 #define AOM_DEC_BORDER_IN_PIXELS 64 typedef struct yv12_buffer_config { @@ -124,6 +125,14 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, int border, int byte_alignment, aom_codec_frame_buffer_t *fb, aom_get_frame_buffer_cb_fn_t cb, void *cb_priv); + +int aom_realloc_lookahead_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, + int ss_x, int ss_y, int use_highbitdepth, + int border, int byte_alignment, + aom_codec_frame_buffer_t *fb, + aom_get_frame_buffer_cb_fn_t cb, + void *cb_priv); + int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf); #ifdef __cplusplus diff --git a/third_party/aom/apps/aomdec.c b/third_party/aom/apps/aomdec.c index c054425777..549c4da617 100644 --- a/third_party/aom/apps/aomdec.c +++ b/third_party/aom/apps/aomdec.c @@ -851,7 +851,7 @@ static int main_loop(int argc, const char **argv_) { } // Default to codec bit depth if output bit depth not set unsigned int output_bit_depth; - if (!fixed_output_bit_depth && single_file && !do_md5) { + if (!fixed_output_bit_depth && single_file) { output_bit_depth = img->bit_depth; } else { output_bit_depth = fixed_output_bit_depth; diff --git a/third_party/aom/apps/aomenc.c b/third_party/aom/apps/aomenc.c index 83c1353de5..08bf08d5b1 100644 --- a/third_party/aom/apps/aomenc.c +++ b/third_party/aom/apps/aomenc.c @@ -144,16 +144,14 @@ static const arg_def_t pass_arg = ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)"); static const arg_def_t fpf_name = ARG_DEF(NULL, "fpf", 1, "First pass statistics file name"); -#if CONFIG_FP_MB_STATS -static const arg_def_t fpmbf_name = - ARG_DEF(NULL, "fpmbf", 1, "First pass block statistics file name"); -#endif static const arg_def_t limit = ARG_DEF(NULL, "limit", 1, "Stop encoding after n input frames"); static const arg_def_t skip = ARG_DEF(NULL, "skip", 1, "Skip the first n input frames"); static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, "Use Good Quality Deadline"); +static const arg_def_t rt_dl = + ARG_DEF(NULL, "rt", 0, "Use Realtime Quality Deadline"); static const arg_def_t quietarg = ARG_DEF("q", "quiet", 0, "Do not print encode progress"); static const arg_def_t verbosearg = @@ -219,6 +217,7 @@ static const arg_def_t *main_args[] = { &help, &limit, &skip, &good_dl, + &rt_dl, &quietarg, &verbosearg, &psnrarg, @@ -441,6 +440,21 @@ static const arg_def_t enable_rect_partitions = ARG_DEF(NULL, "enable-rect-partitions", 1, "Enable rectangular partitions " "(0: false, 1: true (default))"); +static const arg_def_t enable_ab_partitions = + ARG_DEF(NULL, "enable-ab-partitions", 1, + "Enable ab partitions (0: false, 1: true (default))"); +static const arg_def_t enable_1to4_partitions = + ARG_DEF(NULL, "enable-1to4-partitions", 1, + "Enable 1:4 and 4:1 partitions " + "(0: false, 1: true (default))"); +static const arg_def_t min_partition_size = + ARG_DEF(NULL, "min-partition-size", 4, + "Set min partition size " + "(4:4x4, 8:8x8, 16:16x16, 32:32x32, 64:64x64, 128:128x128)"); +static const arg_def_t max_partition_size = + ARG_DEF(NULL, "max-partition-size", 128, + "Set max partition size " + "(4:4x4, 8:8x8, 16:16x16, 32:32x32, 64:64x64, 128:128x128)"); static const arg_def_t enable_dual_filter = ARG_DEF(NULL, "enable-dual-filter", 1, "Enable dual filter " @@ -456,6 +470,16 @@ static const arg_def_t enable_order_hint = static const arg_def_t enable_tx64 = ARG_DEF(NULL, "enable-tx64", 1, "Enable 64-pt transform (0: false, 1: true (default))"); +static const arg_def_t tx_size_search_method = + ARG_DEF(NULL, "tx-size-search-method", 0, + "Set transform block size search method " + "(0: Full RD (default), 1: Fast RD, 2: use largest allowed)"); +static const arg_def_t enable_flip_idtx = + ARG_DEF(NULL, "enable-flip-idtx", 1, + "Enable extended transform type (0: false, 1: true (default)) " + "including FLIPADST_DCT, DCT_FLIPADST, FLIPADST_FLIPADST, " + "ADST_FLIPADST, FLIPADST_ADST, IDTX, V_DCT, H_DCT, V_ADST, " + "H_ADST, V_FLIPADST, H_FLIPADST"); static const arg_def_t enable_dist_wtd_comp = ARG_DEF(NULL, "enable-dist-wtd-comp", 1, "Enable distance-weighted compound " @@ -464,6 +488,10 @@ static const arg_def_t enable_masked_comp = ARG_DEF(NULL, "enable-masked-comp", 1, "Enable masked (wedge/diff-wtd) compound " "(0: false, 1: true (default))"); +static const arg_def_t enable_onesided_comp = + ARG_DEF(NULL, "enable-onesided-comp", 1, + "Enable one sided compound " + "(0: false, 1: true (default))"); static const arg_def_t enable_interintra_comp = ARG_DEF(NULL, "enable-interintra-comp", 1, "Enable interintra compound " @@ -522,7 +550,7 @@ static const arg_def_t enable_angle_delta = static const arg_def_t disable_trellis_quant = ARG_DEF(NULL, "disable-trellis-quant", 1, "Disable trellis optimization of quantized coefficients (0: false (" - "default) 1: true)"); + "default) 1: true 2: partial true)"); static const arg_def_t enable_qm = ARG_DEF(NULL, "enable-qm", 1, "Enable quantisation matrices (0: false (default), 1: true)"); @@ -536,8 +564,19 @@ static const arg_def_t use_intra_dct_only = ARG_DEF(NULL, "use-intra-dct-only", 1, "Use DCT only for INTRA modes"); static const arg_def_t use_inter_dct_only = ARG_DEF(NULL, "use-inter-dct-only", 1, "Use DCT only for INTER modes"); +static const arg_def_t use_intra_default_tx_only = + ARG_DEF(NULL, "use-intra-default-tx-only", 1, + "Use Default-transform only for INTRA modes"); static const arg_def_t quant_b_adapt = ARG_DEF(NULL, "quant-b-adapt", 1, "Use adaptive quantize_b"); +static const arg_def_t coeff_cost_upd_freq = + ARG_DEF(NULL, "coeff-cost-upd-freq", 1, + "Update freq for coeff costs" + "0: SB, 1: SB Row per Tile, 2: Tile"); +static const arg_def_t mode_cost_upd_freq = + ARG_DEF(NULL, "mode-cost-upd-freq", 1, + "Update freq for mode costs" + "0: SB, 1: SB Row per Tile, 2: Tile"); #if CONFIG_DIST_8X8 static const arg_def_t enable_dist_8x8 = ARG_DEF(NULL, "enable-dist-8x8", 1, @@ -607,10 +646,23 @@ static const arg_def_t max_gf_interval = ARG_DEF( "max gf/arf frame interval (default 0, indicating in-built behavior)"); static const arg_def_t gf_max_pyr_height = ARG_DEF(NULL, "gf-max-pyr-height", 1, - "maximum height for GF group pyramid structure (1 to 4 (default))"); + "maximum height for GF group pyramid structure (0 to 4 (default))"); static const arg_def_t max_reference_frames = ARG_DEF( NULL, "max-reference-frames", 1, "maximum number of reference frames allowed per frame (3 to 7 (default))"); +static const arg_def_t reduced_reference_set = + ARG_DEF(NULL, "reduced-reference-set", 1, + "Use reduced set of single and compound references (0: off " + "(default), 1: on)"); +static const arg_def_t target_seq_level_idx = + ARG_DEF(NULL, "target-seq-level-idx", 1, + "Target sequence level index. " + "Possible values are in the form of \"ABxy\"(pad leading zeros if " + "less than 4 digits). " + "AB: Operating point(OP) index; " + "xy: Target level index for the OP. " + "E.g. \"0\" means target level index 0 for the 0th OP; " + "\"1021\" means target level index 21 for the 10th OP."); static const struct arg_enum_list color_primaries_enum[] = { { "bt709", AOM_CICP_CP_BT_709 }, @@ -716,6 +768,12 @@ static const struct arg_enum_list superblock_size_enum[] = { static const arg_def_t superblock_size = ARG_DEF_ENUM( NULL, "sb-size", 1, "Superblock size to use", superblock_size_enum); +static const arg_def_t set_tier_mask = + ARG_DEF(NULL, "set-tier-mask", 1, + "Set bit mask to specify which tier each of the 32 possible " + "operating points conforms to. " + "Bit value 0(defualt): Main Tier; 1: High Tier."); + static const arg_def_t *av1_args[] = { &cpu_used_av1, &auto_altref, &sharpness, @@ -735,12 +793,19 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &enable_cdef, &enable_restoration, &enable_rect_partitions, + &enable_ab_partitions, + &enable_1to4_partitions, + &min_partition_size, + &max_partition_size, &enable_dual_filter, &enable_intra_edge_filter, &enable_order_hint, &enable_tx64, + &tx_size_search_method, + &enable_flip_idtx, &enable_dist_wtd_comp, &enable_masked_comp, + &enable_onesided_comp, &enable_interintra_comp, &enable_smooth_interintra, &enable_diff_wtd_comp, @@ -763,7 +828,10 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &reduced_tx_type_set, &use_intra_dct_only, &use_inter_dct_only, + &use_intra_default_tx_only, &quant_b_adapt, + &coeff_cost_upd_freq, + &mode_cost_upd_freq, #if CONFIG_DIST_8X8 &enable_dist_8x8, #endif @@ -793,7 +861,10 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &denoise_block_size, #endif // CONFIG_DENOISE &max_reference_frames, + &reduced_reference_set, &enable_ref_frame_mvs, + &target_seq_level_idx, + &set_tier_mask, &bitdeptharg, &inbitdeptharg, &input_chroma_subsampling_x, @@ -821,12 +892,19 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AV1E_SET_ENABLE_CDEF, AV1E_SET_ENABLE_RESTORATION, AV1E_SET_ENABLE_RECT_PARTITIONS, + AV1E_SET_ENABLE_AB_PARTITIONS, + AV1E_SET_ENABLE_1TO4_PARTITIONS, + AV1E_SET_MIN_PARTITION_SIZE, + AV1E_SET_MAX_PARTITION_SIZE, AV1E_SET_ENABLE_DUAL_FILTER, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, AV1E_SET_ENABLE_ORDER_HINT, AV1E_SET_ENABLE_TX64, + AV1E_SET_TX_SIZE_SEARCH_METHOD, + AV1E_SET_ENABLE_FLIP_IDTX, AV1E_SET_ENABLE_DIST_WTD_COMP, AV1E_SET_ENABLE_MASKED_COMP, + AV1E_SET_ENABLE_ONESIDED_COMP, AV1E_SET_ENABLE_INTERINTRA_COMP, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, AV1E_SET_ENABLE_DIFF_WTD_COMP, @@ -849,7 +927,10 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AV1E_SET_REDUCED_TX_TYPE_SET, AV1E_SET_INTRA_DCT_ONLY, AV1E_SET_INTER_DCT_ONLY, + AV1E_SET_INTRA_DEFAULT_TX_ONLY, AV1E_SET_QUANT_B_ADAPT, + AV1E_SET_COEFF_COST_UPD_FREQ, + AV1E_SET_MODE_COST_UPD_FREQ, #if CONFIG_DIST_8X8 AV1E_SET_ENABLE_DIST_8X8, #endif @@ -879,7 +960,10 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AV1E_SET_DENOISE_BLOCK_SIZE, #endif // CONFIG_DENOISE AV1E_SET_MAX_REFERENCE_FRAMES, + AV1E_SET_REDUCED_REFERENCE_SET, AV1E_SET_ENABLE_REF_FRAME_MVS, + AV1E_SET_TARGET_SEQ_LEVEL_IDX, + AV1E_SET_TIER_MASK, 0 }; #endif // CONFIG_AV1_ENCODER @@ -946,9 +1030,6 @@ struct stream_config { struct aom_codec_enc_cfg cfg; const char *out_fn; const char *stats_fn; -#if CONFIG_FP_MB_STATS - const char *fpmb_stats_fn; -#endif stereo_format_t stereo_fmt; int arg_ctrls[ARG_CTRL_CNT_MAX][2]; int arg_ctrl_cnt; @@ -976,9 +1057,6 @@ struct stream_state { uint64_t cx_time; size_t nbytes; stats_io_t stats; -#if CONFIG_FP_MB_STATS - stats_io_t fpmb_stats; -#endif struct aom_image *img; aom_codec_ctx_t decoder; int mismatch_seen; @@ -1064,7 +1142,9 @@ static void parse_global_config(struct AvxEncoderConfig *global, int argc, } else if (arg_match(&arg, &usage, argi)) global->usage = arg_parse_uint(&arg); else if (arg_match(&arg, &good_dl, argi)) - warn("Deprecated --good option! Ignoring\n"); + global->usage = AOM_USAGE_GOOD_QUALITY; // Good quality usage + else if (arg_match(&arg, &rt_dl, argi)) + global->usage = AOM_USAGE_REALTIME; // Real-time usage else if (arg_match(&arg, &use_yv12, argi)) global->color_type = YV12; else if (arg_match(&arg, &use_i420, argi)) @@ -1117,11 +1197,19 @@ static void parse_global_config(struct AvxEncoderConfig *global, int argc, // Make default AV1 passes = 2 until there is a better quality 1-pass // encoder if (global->codec != NULL && global->codec->name != NULL) - global->passes = (strcmp(global->codec->name, "av1") == 0) ? 2 : 1; + global->passes = (strcmp(global->codec->name, "av1") == 0 && + global->usage != AOM_USAGE_REALTIME) + ? 2 + : 1; #else global->passes = 1; #endif } + + if (global->usage == AOM_USAGE_REALTIME && global->passes > 1) { + warn("Enforcing one-pass encoding in realtime mode\n"); + global->passes = 1; + } } static void open_input_file(struct AvxInputContext *input, @@ -1238,6 +1326,17 @@ static void set_config_arg_ctrls(struct stream_config *config, int key, return; } + // For target level, the settings should accumulate rather than overwrite, + // so we simply append it. + if (key == AV1E_SET_TARGET_SEQ_LEVEL_IDX) { + j = config->arg_ctrl_cnt; + assert(j < (int)ARG_CTRL_CNT_MAX); + config->arg_ctrls[j][0] = key; + config->arg_ctrls[j][1] = arg_parse_enum_or_int(arg); + ++config->arg_ctrl_cnt; + return; + } + /* Point either to the next free element or the first instance of this * control. */ @@ -1307,10 +1406,6 @@ static int parse_stream_params(struct AvxEncoderConfig *global, } } else if (arg_match(&arg, &fpf_name, argi)) { config->stats_fn = arg.val; -#if CONFIG_FP_MB_STATS - } else if (arg_match(&arg, &fpmbf_name, argi)) { - config->fpmb_stats_fn = arg.val; -#endif } else if (arg_match(&arg, &use_webm, argi)) { #if CONFIG_WEBM_IO config->write_webm = 1; @@ -1355,6 +1450,12 @@ static int parse_stream_params(struct AvxEncoderConfig *global, config->cfg.g_error_resilient = arg_parse_uint(&arg); } else if (arg_match(&arg, &lag_in_frames, argi)) { config->cfg.g_lag_in_frames = arg_parse_uint(&arg); + if (global->usage == AOM_USAGE_REALTIME && + config->cfg.rc_end_usage == AOM_CBR && + config->cfg.g_lag_in_frames != 0) { + warn("non-zero %s option ignored in realtime CBR mode.\n", arg.name); + config->cfg.g_lag_in_frames = 0; + } } else if (arg_match(&arg, &large_scale_tile, argi)) { config->cfg.large_scale_tile = arg_parse_uint(&arg); if (config->cfg.large_scale_tile) global->codec = get_aom_lst_encoder(); @@ -1498,17 +1599,6 @@ static void validate_stream_config(const struct stream_state *stream, fatal("Stream %d: duplicate stats file (from stream %d)", streami->index, stream->index); } - -#if CONFIG_FP_MB_STATS - /* Check for two streams sharing a mb stats file. */ - if (streami != stream) { - const char *a = stream->config.fpmb_stats_fn; - const char *b = streami->config.fpmb_stats_fn; - if (a && b && !strcmp(a, b)) - fatal("Stream %d: duplicate mb stats file (from stream %d)", - streami->index, stream->index); - } -#endif } } @@ -1673,26 +1763,11 @@ static void setup_pass(struct stream_state *stream, fatal("Failed to open statistics store"); } -#if CONFIG_FP_MB_STATS - if (stream->config.fpmb_stats_fn) { - if (!stats_open_file(&stream->fpmb_stats, stream->config.fpmb_stats_fn, - pass)) - fatal("Failed to open mb statistics store"); - } else { - if (!stats_open_mem(&stream->fpmb_stats, pass)) - fatal("Failed to open mb statistics store"); - } -#endif - stream->config.cfg.g_pass = global->passes == 2 ? pass ? AOM_RC_LAST_PASS : AOM_RC_FIRST_PASS : AOM_RC_ONE_PASS; if (pass) { stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); -#if CONFIG_FP_MB_STATS - stream->config.cfg.rc_firstpass_mb_stats_in = - stats_get(&stream->fpmb_stats); -#endif } stream->cx_time = 0; @@ -1921,13 +1996,6 @@ static void get_cx_data(struct stream_state *stream, pkt->data.twopass_stats.sz); stream->nbytes += pkt->data.raw.sz; break; -#if CONFIG_FP_MB_STATS - case AOM_CODEC_FPMB_STATS_PKT: - stats_write(&stream->fpmb_stats, pkt->data.firstpass_mb_stats.buf, - pkt->data.firstpass_mb_stats.sz); - stream->nbytes += pkt->data.raw.sz; - break; -#endif case AOM_CODEC_PSNR_PKT: if (global->show_psnr) { @@ -2524,12 +2592,6 @@ int main(int argc, const char **argv_) { stats_close(&stream->stats, global.passes - 1); } -#if CONFIG_FP_MB_STATS - FOREACH_STREAM(stream, streams) { - stats_close(&stream->fpmb_stats, global.passes - 1); - } -#endif - if (global.pass) break; } diff --git a/third_party/aom/av1/av1.cmake b/third_party/aom/av1/av1.cmake index 0b4901a619..fb9678a8ea 100644 --- a/third_party/aom/av1/av1.cmake +++ b/third_party/aom/av1/av1.cmake @@ -151,6 +151,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/firstpass.h" "${AOM_ROOT}/av1/encoder/global_motion.c" "${AOM_ROOT}/av1/encoder/global_motion.h" + "${AOM_ROOT}/av1/encoder/gop_structure.c" + "${AOM_ROOT}/av1/encoder/gop_structure.h" "${AOM_ROOT}/av1/encoder/grain_test_vectors.h" "${AOM_ROOT}/av1/encoder/hash.c" "${AOM_ROOT}/av1/encoder/hash.h" @@ -158,6 +160,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/hash_motion.h" "${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.c" "${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.h" + "${AOM_ROOT}/av1/encoder/level.c" + "${AOM_ROOT}/av1/encoder/level.h" "${AOM_ROOT}/av1/encoder/lookahead.c" "${AOM_ROOT}/av1/encoder/lookahead.h" "${AOM_ROOT}/av1/encoder/mbgraph.c" @@ -168,6 +172,10 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/ml.h" "${AOM_ROOT}/av1/encoder/palette.c" "${AOM_ROOT}/av1/encoder/palette.h" + "${AOM_ROOT}/av1/encoder/partition_strategy.h" + "${AOM_ROOT}/av1/encoder/partition_strategy.c" + "${AOM_ROOT}/av1/encoder/pass2_strategy.h" + "${AOM_ROOT}/av1/encoder/pass2_strategy.c" "${AOM_ROOT}/av1/encoder/pickcdef.c" "${AOM_ROOT}/av1/encoder/picklpf.c" "${AOM_ROOT}/av1/encoder/picklpf.h" @@ -194,6 +202,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/tpl_model.c" "${AOM_ROOT}/av1/encoder/tpl_model.h" "${AOM_ROOT}/av1/encoder/wedge_utils.c" + "${AOM_ROOT}/av1/encoder/var_based_part.c" + "${AOM_ROOT}/av1/encoder/var_based_part.h" "${AOM_ROOT}/third_party/fastfeat/fast.c" "${AOM_ROOT}/third_party/fastfeat/fast.h" "${AOM_ROOT}/third_party/fastfeat/fast_9.c" @@ -257,8 +267,7 @@ list(APPEND AOM_AV1_COMMON_INTRIN_AVX2 "${AOM_ROOT}/av1/common/x86/wiener_convolve_avx2.c") list(APPEND AOM_AV1_ENCODER_ASM_SSE2 "${AOM_ROOT}/av1/encoder/x86/dct_sse2.asm" - "${AOM_ROOT}/av1/encoder/x86/error_sse2.asm" - "${AOM_ROOT}/av1/encoder/x86/temporal_filter_apply_sse2.asm") + "${AOM_ROOT}/av1/encoder/x86/error_sse2.asm") list(APPEND AOM_AV1_ENCODER_INTRIN_SSE2 "${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm_sse2.c" @@ -281,6 +290,9 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_SSE4_1 "${AOM_ROOT}/av1/encoder/x86/encodetxb_sse4.c" "${AOM_ROOT}/av1/encoder/x86/highbd_fwd_txfm_sse4.c" "${AOM_ROOT}/av1/encoder/x86/rdopt_sse4.c" + "${AOM_ROOT}/av1/encoder/x86/temporal_filter_constants.h" + "${AOM_ROOT}/av1/encoder/x86/temporal_filter_sse4.c" + "${AOM_ROOT}/av1/encoder/x86/highbd_temporal_filter_sse4.c" "${AOM_ROOT}/av1/encoder/x86/pickrst_sse4.c") list(APPEND AOM_AV1_ENCODER_INTRIN_AVX2 @@ -288,6 +300,7 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_AVX2 "${AOM_ROOT}/av1/encoder/x86/av1_highbd_quantize_avx2.c" "${AOM_ROOT}/av1/encoder/x86/corner_match_avx2.c" "${AOM_ROOT}/av1/encoder/x86/error_intrin_avx2.c" + "${AOM_ROOT}/av1/encoder/x86/highbd_block_error_intrin_avx2.c" "${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm_avx2.h" "${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm2d_avx2.c" "${AOM_ROOT}/av1/encoder/x86/highbd_fwd_txfm_avx2.c" @@ -346,15 +359,7 @@ endif() function(setup_av1_targets) add_library(aom_av1_common OBJECT ${AOM_AV1_COMMON_SOURCES}) list(APPEND AOM_LIB_TARGETS aom_av1_common) - - create_dummy_source_file("aom_av1" "c" "dummy_source_file") - add_library(aom_av1 OBJECT "${dummy_source_file}") target_sources(aom PRIVATE $) - list(APPEND AOM_LIB_TARGETS aom_av1) - - # Not all generators support libraries consisting only of object files. Add a - # dummy source file to the aom_av1 target. - add_dummy_source_file_to_target("aom_av1" "c") if(CONFIG_AV1_DECODER) add_library(aom_av1_decoder OBJECT ${AOM_AV1_DECODER_SOURCES}) @@ -452,13 +457,13 @@ function(setup_av1_targets) if(HAVE_NEON) if(AOM_AV1_COMMON_INTRIN_NEON) - add_intrinsics_object_library("${AOM_INTRIN_NEON_FLAG}" "neon" + add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon" "aom_av1_common" "AOM_AV1_COMMON_INTRIN_NEON" "aom") endif() if(AOM_AV1_ENCODER_INTRIN_NEON) - add_intrinsics_object_library("${AOM_INTRIN_NEON_FLAG}" "neon" + add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon" "aom_av1_encoder" "AOM_AV1_ENCODER_INTRIN_NEON" "aom") endif() @@ -476,13 +481,7 @@ function(setup_av1_targets) "AOM_AV1_ENCODER_INTRIN_MSA" "aom") endif() - target_sources(aom PRIVATE $) - target_sources(aom PRIVATE $) - # Pass the new lib targets up to the parent scope instance of # $AOM_LIB_TARGETS. set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE) endfunction() - -function(setup_av1_test_targets) -endfunction() diff --git a/third_party/aom/av1/av1_cx_iface.c b/third_party/aom/av1/av1_cx_iface.c index 285e6a5086..e8cd508cc4 100644 --- a/third_party/aom/av1/av1_cx_iface.c +++ b/third_party/aom/av1/av1_cx_iface.c @@ -92,26 +92,34 @@ struct av1_extracfg { unsigned int motion_vector_unit_test; unsigned int cdf_update_mode; int enable_rect_partitions; // enable rectangular partitions for sequence + int enable_ab_partitions; // enable AB partitions for sequence + int enable_1to4_partitions; // enable 1:4 and 4:1 partitions for sequence + int min_partition_size; // min partition size [4,8,16,32,64,128] + int max_partition_size; // max partition size [4,8,16,32,64,128] int enable_intra_edge_filter; // enable intra-edge filter for sequence int enable_order_hint; // enable order hint for sequence int enable_tx64; // enable 64-pt transform usage for sequence + int tx_size_search_method; // set transform block size search method + int enable_flip_idtx; // enable flip and identity transform types int enable_dist_wtd_comp; // enable dist wtd compound for sequence int max_reference_frames; // maximum number of references per frame - int enable_ref_frame_mvs; // sequence level - int allow_ref_frame_mvs; // frame level - int enable_masked_comp; // enable masked compound for sequence - int enable_interintra_comp; // enable interintra compound for sequence - int enable_smooth_interintra; // enable smooth interintra mode usage - int enable_diff_wtd_comp; // enable diff-wtd compound usage - int enable_interinter_wedge; // enable interinter-wedge compound usage - int enable_interintra_wedge; // enable interintra-wedge compound usage - int enable_global_motion; // enable global motion usage for sequence - int enable_warped_motion; // sequence level - int allow_warped_motion; // frame level - int enable_filter_intra; // enable filter intra for sequence - int enable_smooth_intra; // enable smooth intra modes for sequence - int enable_paeth_intra; // enable Peeth intra mode for sequence - int enable_cfl_intra; // enable CFL uv intra mode for sequence + int enable_reduced_reference_set; // enable reduced set of references + int enable_ref_frame_mvs; // sequence level + int allow_ref_frame_mvs; // frame level + int enable_masked_comp; // enable masked compound for sequence + int enable_onesided_comp; // enable one sided compound for sequence + int enable_interintra_comp; // enable interintra compound for sequence + int enable_smooth_interintra; // enable smooth interintra mode usage + int enable_diff_wtd_comp; // enable diff-wtd compound usage + int enable_interinter_wedge; // enable interinter-wedge compound usage + int enable_interintra_wedge; // enable interintra-wedge compound usage + int enable_global_motion; // enable global motion usage for sequence + int enable_warped_motion; // sequence level + int allow_warped_motion; // frame level + int enable_filter_intra; // enable filter intra for sequence + int enable_smooth_intra; // enable smooth intra modes for sequence + int enable_paeth_intra; // enable Paeth intra mode for sequence + int enable_cfl_intra; // enable CFL uv intra mode for sequence int enable_superres; int enable_palette; int enable_intrabc; @@ -126,7 +134,14 @@ struct av1_extracfg { int reduced_tx_type_set; int use_intra_dct_only; int use_inter_dct_only; + int use_intra_default_tx_only; int quant_b_adapt; + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; + // Bit mask to specify which tier each of the 32 possible operating points + // conforms to. + unsigned int tier_mask; + COST_UPDATE_TYPE coeff_cost_upd_freq; + COST_UPDATE_TYPE mode_cost_upd_freq; }; static struct av1_extracfg default_extra_cfg = { @@ -167,7 +182,7 @@ static struct av1_extracfg default_extra_cfg = { 1, // max number of tile groups 0, // mtu_size AOM_TIMING_UNSPECIFIED, // No picture timing signaling in bitstream - 1, // frame_parallel_decoding_mode + 0, // frame_parallel_decoding_mode 1, // enable dual filter NO_AQ, // aq_mode NO_DELTA_Q, // deltaq_mode @@ -190,14 +205,22 @@ static struct av1_extracfg default_extra_cfg = { 0, // motion_vector_unit_test 1, // CDF update mode 1, // enable rectangular partitions + 1, // enable ab shape partitions + 1, // enable 1:4 and 4:1 partitions + 4, // min_partition_size + 128, // max_partition_size 1, // enable intra edge filter 1, // frame order hint 1, // enable 64-pt transform usage + 0, // transform block size search method + 1, // enable flip and identity transform 1, // dist-wtd compound 7, // max_reference_frames + 0, // enable_reduced_reference_set 1, // enable_ref_frame_mvs sequence level 1, // allow ref_frame_mvs frame level 1, // enable masked compound at sequence level + 1, // enable one sided compound at sequence level 1, // enable interintra compound at sequence level 1, // enable smooth interintra mode 1, // enable difference-weighted compound @@ -212,7 +235,7 @@ static struct av1_extracfg default_extra_cfg = { 1, // enable CFL uv intra mode usage for sequence 1, // superres 1, // enable palette - 1, // enable intrabc + !CONFIG_SHARP_SETTINGS, // enable intrabc 1, // enable angle delta #if CONFIG_DENOISE 0, // noise_level @@ -223,7 +246,15 @@ static struct av1_extracfg default_extra_cfg = { 0, // reduced_tx_type_set 0, // use_intra_dct_only 0, // use_inter_dct_only + 0, // use_intra_default_tx_only 0, // quant_b_adapt + { + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + }, // target_seq_level_idx + 0, // tier_mask + COST_UPD_SB, // coeff_cost_upd_freq + COST_UPD_SB, // mode_cost_upd_freq }; struct aom_codec_alg_priv { @@ -295,6 +326,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, RANGE_CHECK_HI(extra_cfg, aq_mode, AQ_MODE_COUNT - 1); RANGE_CHECK_HI(extra_cfg, deltaq_mode, DELTAQ_MODE_COUNT - 1); RANGE_CHECK_HI(extra_cfg, frame_periodic_boost, 1); + RANGE_CHECK_HI(cfg, g_usage, 1); RANGE_CHECK_HI(cfg, g_threads, MAX_NUM_THREADS); RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS); RANGE_CHECK(cfg, rc_end_usage, AOM_VBR, AOM_Q); @@ -310,7 +342,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, RANGE_CHECK(extra_cfg, max_gf_interval, MAX(2, extra_cfg->min_gf_interval), (MAX_LAG_BUFFERS - 1)); } - RANGE_CHECK(extra_cfg, gf_max_pyr_height, 1, 4); + RANGE_CHECK_HI(extra_cfg, gf_max_pyr_height, 4); RANGE_CHECK_HI(cfg, rc_resize_mode, RESIZE_MODES - 1); RANGE_CHECK(cfg, rc_resize_denominator, SCALE_NUMERATOR, @@ -428,9 +460,25 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, } RANGE_CHECK(extra_cfg, max_reference_frames, 3, 7); + RANGE_CHECK(extra_cfg, enable_reduced_reference_set, 0, 1); RANGE_CHECK_HI(extra_cfg, chroma_subsampling_x, 1); RANGE_CHECK_HI(extra_cfg, chroma_subsampling_y, 1); + RANGE_CHECK_HI(extra_cfg, disable_trellis_quant, 3); + RANGE_CHECK(extra_cfg, coeff_cost_upd_freq, 0, 2); + RANGE_CHECK(extra_cfg, mode_cost_upd_freq, 0, 2); + + RANGE_CHECK(extra_cfg, min_partition_size, 4, 128); + RANGE_CHECK(extra_cfg, max_partition_size, 4, 128); + RANGE_CHECK_HI(extra_cfg, min_partition_size, extra_cfg->max_partition_size); + + RANGE_CHECK(extra_cfg, tx_size_search_method, 0, 2); + + for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { + if (!is_valid_seq_level_idx(extra_cfg->target_seq_level_idx[i])) + ERROR("Target sequence level index is invalid"); + } + return AOM_CODEC_OK; } @@ -498,6 +546,7 @@ static aom_codec_err_t set_encoder_config( oxcf->profile = cfg->g_profile; oxcf->fwd_kf_enabled = cfg->fwd_kf_enabled; oxcf->max_threads = (int)cfg->g_threads; + oxcf->mode = (cfg->g_usage == 1) ? REALTIME : GOOD; oxcf->width = cfg->g_w; oxcf->height = cfg->g_h; oxcf->forced_max_frame_width = cfg->g_forced_max_frame_width; @@ -540,7 +589,6 @@ static aom_codec_err_t set_encoder_config( oxcf->init_framerate = 30; oxcf->timing_info_present = 0; } - oxcf->mode = GOOD; oxcf->cfg = &cfg->cfg; switch (cfg->g_pass) { @@ -582,7 +630,10 @@ static aom_codec_err_t set_encoder_config( oxcf->reduced_tx_type_set = extra_cfg->reduced_tx_type_set; oxcf->use_intra_dct_only = extra_cfg->use_intra_dct_only; oxcf->use_inter_dct_only = extra_cfg->use_inter_dct_only; + oxcf->use_intra_default_tx_only = extra_cfg->use_intra_default_tx_only; oxcf->quant_b_adapt = extra_cfg->quant_b_adapt; + oxcf->coeff_cost_upd_freq = (COST_UPDATE_TYPE)extra_cfg->coeff_cost_upd_freq; + oxcf->mode_cost_upd_freq = (COST_UPDATE_TYPE)extra_cfg->mode_cost_upd_freq; #if CONFIG_DIST_8X8 oxcf->using_dist_8x8 = extra_cfg->enable_dist_8x8; if (extra_cfg->tuning == AOM_TUNE_CDEF_DIST || @@ -660,10 +711,6 @@ static aom_codec_err_t set_encoder_config( oxcf->two_pass_stats_in = cfg->rc_twopass_stats_in; -#if CONFIG_FP_MB_STATS - oxcf->firstpass_mb_stats_in = cfg->rc_firstpass_mb_stats_in; -#endif - oxcf->color_primaries = extra_cfg->color_primaries; oxcf->transfer_characteristics = extra_cfg->transfer_characteristics; oxcf->matrix_coefficients = extra_cfg->matrix_coefficients; @@ -718,17 +765,21 @@ static aom_codec_err_t set_encoder_config( oxcf->full_still_picture_hdr = cfg->full_still_picture_hdr; oxcf->enable_dual_filter = extra_cfg->enable_dual_filter; oxcf->enable_rect_partitions = extra_cfg->enable_rect_partitions; + oxcf->enable_ab_partitions = extra_cfg->enable_ab_partitions; + oxcf->enable_1to4_partitions = extra_cfg->enable_1to4_partitions; + oxcf->min_partition_size = extra_cfg->min_partition_size; + oxcf->max_partition_size = extra_cfg->max_partition_size; oxcf->enable_intra_edge_filter = extra_cfg->enable_intra_edge_filter; oxcf->enable_tx64 = extra_cfg->enable_tx64; + oxcf->tx_size_search_method = extra_cfg->tx_size_search_method; + oxcf->enable_flip_idtx = extra_cfg->enable_flip_idtx; oxcf->enable_order_hint = extra_cfg->enable_order_hint; oxcf->enable_dist_wtd_comp = extra_cfg->enable_dist_wtd_comp & extra_cfg->enable_order_hint; oxcf->max_reference_frames = extra_cfg->max_reference_frames; - if (oxcf->max_reference_frames > 3 && oxcf->max_reference_frames < 7) { - // TODO(urvang): Enable all possible values, after they work properly. - oxcf->max_reference_frames = 3; - } + oxcf->enable_reduced_reference_set = extra_cfg->enable_reduced_reference_set; oxcf->enable_masked_comp = extra_cfg->enable_masked_comp; + oxcf->enable_onesided_comp = extra_cfg->enable_onesided_comp; oxcf->enable_diff_wtd_comp = extra_cfg->enable_masked_comp & extra_cfg->enable_diff_wtd_comp; oxcf->enable_interinter_wedge = @@ -795,6 +846,9 @@ static aom_codec_err_t set_encoder_config( oxcf->border_in_pixels = (oxcf->resize_mode || oxcf->superres_mode) ? AOM_BORDER_IN_PIXELS : AOM_ENC_NO_SCALE_BORDER; + memcpy(oxcf->target_seq_level_idx, extra_cfg->target_seq_level_idx, + sizeof(oxcf->target_seq_level_idx)); + oxcf->tier_mask = extra_cfg->tier_mask; return AOM_CODEC_OK; } @@ -1097,6 +1151,35 @@ static aom_codec_err_t ctrl_set_enable_rect_partitions( return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_enable_ab_partitions(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.enable_ab_partitions = CAST(AV1E_SET_ENABLE_AB_PARTITIONS, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_enable_1to4_partitions( + aom_codec_alg_priv_t *ctx, va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.enable_1to4_partitions = + CAST(AV1E_SET_ENABLE_1TO4_PARTITIONS, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_min_partition_size(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.min_partition_size = CAST(AV1E_SET_MIN_PARTITION_SIZE, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_max_partition_size(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.max_partition_size = CAST(AV1E_SET_MAX_PARTITION_SIZE, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_enable_intra_edge_filter( aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1119,6 +1202,20 @@ static aom_codec_err_t ctrl_set_enable_tx64(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_tx_size_search_method(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.tx_size_search_method = CAST(AV1E_SET_TX_SIZE_SEARCH_METHOD, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_enable_flip_idtx(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.enable_flip_idtx = CAST(AV1E_SET_ENABLE_FLIP_IDTX, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_enable_dist_wtd_comp(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1133,6 +1230,14 @@ static aom_codec_err_t ctrl_set_max_reference_frames(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_enable_reduced_reference_set( + aom_codec_alg_priv_t *ctx, va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.enable_reduced_reference_set = + CAST(AV1E_SET_REDUCED_REFERENCE_SET, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_enable_ref_frame_mvs(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1154,6 +1259,13 @@ static aom_codec_err_t ctrl_set_enable_masked_comp(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_enable_onesided_comp(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.enable_onesided_comp = CAST(AV1E_SET_ENABLE_ONESIDED_COMP, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_enable_interintra_comp( aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1327,6 +1439,14 @@ static aom_codec_err_t ctrl_set_inter_dct_only(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_intra_default_tx_only(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.use_intra_default_tx_only = + CAST(AV1E_SET_INTRA_DEFAULT_TX_ONLY, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_quant_b_adapt(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1334,6 +1454,20 @@ static aom_codec_err_t ctrl_set_quant_b_adapt(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_coeff_cost_upd_freq(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.coeff_cost_upd_freq = CAST(AV1E_SET_COEFF_COST_UPD_FREQ, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_mode_cost_upd_freq(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.mode_cost_upd_freq = CAST(AV1E_SET_MODE_COST_UPD_FREQ, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_film_grain_test_vector( aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1409,6 +1543,26 @@ static aom_codec_err_t ctrl_enable_motion_vector_unit_test( return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_target_seq_level_idx(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + const int val = CAST(AV1E_SET_TARGET_SEQ_LEVEL_IDX, args); + const int level = val % 100; + const int operating_point_idx = val / 100; + if (operating_point_idx >= 0 && + operating_point_idx < MAX_NUM_OPERATING_POINTS) { + extra_cfg.target_seq_level_idx[operating_point_idx] = (AV1_LEVEL)level; + } + return update_extra_cfg(ctx, &extra_cfg); +} + +static aom_codec_err_t ctrl_set_tier_mask(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.tier_mask = CAST(AV1E_SET_TIER_MASK, 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; @@ -1511,8 +1665,7 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, } } } - - if (ctx->oxcf.mode != GOOD) { + if (ctx->oxcf.mode != GOOD && ctx->oxcf.mode != REALTIME) { ctx->oxcf.mode = GOOD; av1_change_config(ctx->cpi, &ctx->oxcf); } @@ -1570,6 +1723,8 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, unsigned char *cx_data = ctx->cx_data; size_t cx_data_sz = ctx->cx_data_sz; + assert(!(cx_data == NULL && cx_data_sz != 0)); + /* Any pending invisible frames? */ if (ctx->pending_cx_data) { memmove(cx_data, ctx->pending_cx_data, ctx->pending_cx_data_sz); @@ -1616,8 +1771,8 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, frame_size); } const uint32_t obu_header_offset = 0; - obu_header_size = write_obu_header( - OBU_TEMPORAL_DELIMITER, 0, + obu_header_size = av1_write_obu_header( + cpi, OBU_TEMPORAL_DELIMITER, 0, (uint8_t *)(ctx->pending_cx_data + obu_header_offset)); // OBUs are preceded/succeeded by an unsigned leb128 coded integer. @@ -1978,6 +2133,13 @@ static aom_codec_err_t ctrl_set_chroma_subsampling_y(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_get_seq_level_idx(aom_codec_alg_priv_t *ctx, + va_list args) { + int *const arg = va_arg(args, int *); + if (arg == NULL) return AOM_CODEC_INVALID_PARAM; + return av1_get_seq_level_idx(ctx->cpi, arg); +} + static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1_COPY_REFERENCE, ctrl_copy_reference }, { AOME_USE_REFERENCE, ctrl_use_reference }, @@ -2027,15 +2189,23 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1E_SET_ERROR_RESILIENT_MODE, ctrl_set_error_resilient_mode }, { AV1E_SET_S_FRAME_MODE, ctrl_set_s_frame_mode }, { AV1E_SET_ENABLE_RECT_PARTITIONS, ctrl_set_enable_rect_partitions }, + { AV1E_SET_ENABLE_AB_PARTITIONS, ctrl_set_enable_ab_partitions }, + { AV1E_SET_ENABLE_1TO4_PARTITIONS, ctrl_set_enable_1to4_partitions }, + { AV1E_SET_MIN_PARTITION_SIZE, ctrl_set_min_partition_size }, + { AV1E_SET_MAX_PARTITION_SIZE, ctrl_set_max_partition_size }, { AV1E_SET_ENABLE_DUAL_FILTER, ctrl_set_enable_dual_filter }, { AV1E_SET_ENABLE_INTRA_EDGE_FILTER, ctrl_set_enable_intra_edge_filter }, { AV1E_SET_ENABLE_ORDER_HINT, ctrl_set_enable_order_hint }, { AV1E_SET_ENABLE_TX64, ctrl_set_enable_tx64 }, + { AV1E_SET_TX_SIZE_SEARCH_METHOD, ctrl_set_tx_size_search_method }, + { AV1E_SET_ENABLE_FLIP_IDTX, ctrl_set_enable_flip_idtx }, { AV1E_SET_ENABLE_DIST_WTD_COMP, ctrl_set_enable_dist_wtd_comp }, { AV1E_SET_MAX_REFERENCE_FRAMES, ctrl_set_max_reference_frames }, + { AV1E_SET_REDUCED_REFERENCE_SET, ctrl_set_enable_reduced_reference_set }, { AV1E_SET_ENABLE_REF_FRAME_MVS, ctrl_set_enable_ref_frame_mvs }, { AV1E_SET_ALLOW_REF_FRAME_MVS, ctrl_set_allow_ref_frame_mvs }, { AV1E_SET_ENABLE_MASKED_COMP, ctrl_set_enable_masked_comp }, + { AV1E_SET_ENABLE_ONESIDED_COMP, ctrl_set_enable_onesided_comp }, { AV1E_SET_ENABLE_INTERINTRA_COMP, ctrl_set_enable_interintra_comp }, { AV1E_SET_ENABLE_SMOOTH_INTERINTRA, ctrl_set_enable_smooth_interintra }, { AV1E_SET_ENABLE_DIFF_WTD_COMP, ctrl_set_enable_diff_wtd_comp }, @@ -2056,7 +2226,10 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1E_SET_REDUCED_TX_TYPE_SET, ctrl_set_reduced_tx_type_set }, { AV1E_SET_INTRA_DCT_ONLY, ctrl_set_intra_dct_only }, { AV1E_SET_INTER_DCT_ONLY, ctrl_set_inter_dct_only }, + { AV1E_SET_INTRA_DEFAULT_TX_ONLY, ctrl_set_intra_default_tx_only }, { AV1E_SET_QUANT_B_ADAPT, ctrl_set_quant_b_adapt }, + { AV1E_SET_COEFF_COST_UPD_FREQ, ctrl_set_coeff_cost_upd_freq }, + { AV1E_SET_MODE_COST_UPD_FREQ, ctrl_set_mode_cost_upd_freq }, { AV1E_SET_DELTAQ_MODE, ctrl_set_deltaq_mode }, { AV1E_SET_FRAME_PERIODIC_BOOST, ctrl_set_frame_periodic_boost }, { AV1E_SET_TUNE_CONTENT, ctrl_set_tune_content }, @@ -2080,6 +2253,8 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1E_SET_DENOISE_BLOCK_SIZE, ctrl_set_denoise_block_size }, #endif // CONFIG_FILM_GRAIN { AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test }, + { AV1E_SET_TARGET_SEQ_LEVEL_IDX, ctrl_set_target_seq_level_idx }, + { AV1E_SET_TIER_MASK, ctrl_set_tier_mask }, // Getters { AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer }, @@ -2090,6 +2265,7 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1_COPY_NEW_FRAME_IMAGE, ctrl_copy_new_frame_image }, { AV1E_SET_CHROMA_SUBSAMPLING_X, ctrl_set_chroma_subsampling_x }, { AV1E_SET_CHROMA_SUBSAMPLING_Y, ctrl_set_chroma_subsampling_y }, + { AV1E_GET_SEQ_LEVEL_IDX, ctrl_get_seq_level_idx }, { -1, NULL }, }; @@ -2097,7 +2273,7 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { { 0, { // NOLINT - 0, // g_usage + 0, // g_usage - non-realtime usage 0, // g_threads 0, // g_profile @@ -2122,7 +2298,7 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { SCALE_NUMERATOR, // rc_resize_denominator SCALE_NUMERATOR, // rc_resize_kf_denominator - 0, // rc_superres_mode + SUPERRES_NONE, // rc_superres_mode SCALE_NUMERATOR, // rc_superres_denominator SCALE_NUMERATOR, // rc_superres_kf_denominator 63, // rc_superres_qthresh @@ -2145,6 +2321,74 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { 0, // rc_two_pass_vbrmin_section 2000, // rc_two_pass_vbrmax_section + // keyframing settings (kf) + 0, // fwd_kf_enabled + AOM_KF_AUTO, // g_kfmode + 0, // kf_min_dist + 9999, // kf_max_dist + 0, // sframe_dist + 1, // sframe_mode + 0, // large_scale_tile + 0, // monochrome + 0, // full_still_picture_hdr + 0, // save_as_annexb + 0, // tile_width_count + 0, // tile_height_count + { 0 }, // tile_widths + { 0 }, // tile_heights + { 1 }, // config file + } }, + { 1, + { + // NOLINT + 1, // g_usage - real-time usage + 0, // g_threads + 0, // g_profile + + 320, // g_width + 240, // g_height + 0, // g_limit + 0, // g_forced_max_frame_width + 0, // g_forced_max_frame_height + AOM_BITS_8, // g_bit_depth + 8, // g_input_bit_depth + + { 1, 30 }, // g_timebase + + 0, // g_error_resilient + + AOM_RC_ONE_PASS, // g_pass + + 1, // g_lag_in_frames + + 0, // rc_dropframe_thresh + RESIZE_NONE, // rc_resize_mode + SCALE_NUMERATOR, // rc_resize_denominator + SCALE_NUMERATOR, // rc_resize_kf_denominator + + 0, // rc_superres_mode + SCALE_NUMERATOR, // rc_superres_denominator + SCALE_NUMERATOR, // rc_superres_kf_denominator + 63, // rc_superres_qthresh + 32, // rc_superres_kf_qthresh + + AOM_CBR, // rc_end_usage + { NULL, 0 }, // rc_twopass_stats_in + { NULL, 0 }, // rc_firstpass_mb_stats_in + 256, // rc_target_bandwidth + 0, // rc_min_quantizer + 63, // rc_max_quantizer + 25, // rc_undershoot_pct + 25, // rc_overshoot_pct + + 6000, // rc_max_buffer_size + 4000, // rc_buffer_initial_size + 5000, // rc_buffer_optimal_size + + 50, // rc_two_pass_vbrbias + 0, // rc_two_pass_vbrmin_section + 2000, // rc_two_pass_vbrmax_section + // keyframing settings (kf) 0, // fwd_kf_enabled AOM_KF_AUTO, // g_kfmode @@ -2185,7 +2429,7 @@ CODEC_INTERFACE(aom_codec_av1_cx) = { }, { // NOLINT - 1, // 1 cfg map + 2, // 2 cfg map encoder_usage_cfg_map, // aom_codec_enc_cfg_map_t encoder_encode, // aom_codec_encode_fn_t encoder_get_cxdata, // aom_codec_get_cx_data_fn_t diff --git a/third_party/aom/av1/av1_dx_iface.c b/third_party/aom/av1/av1_dx_iface.c index 87a6e3dca0..ca872d73e1 100644 --- a/third_party/aom/av1/av1_dx_iface.c +++ b/third_party/aom/av1/av1_dx_iface.c @@ -154,6 +154,49 @@ static aom_codec_err_t decoder_destroy(aom_codec_alg_priv_t *ctx) { return AOM_CODEC_OK; } +static aom_codec_err_t parse_timing_info(struct aom_read_bit_buffer *rb) { + const uint32_t num_units_in_display_tick = + aom_rb_read_unsigned_literal(rb, 32); + const uint32_t time_scale = aom_rb_read_unsigned_literal(rb, 32); + if (num_units_in_display_tick == 0 || time_scale == 0) + return AOM_CODEC_UNSUP_BITSTREAM; + const uint8_t equal_picture_interval = aom_rb_read_bit(rb); + if (equal_picture_interval) { + const uint32_t num_ticks_per_picture_minus_1 = aom_rb_read_uvlc(rb); + if (num_ticks_per_picture_minus_1 == UINT32_MAX) { + // num_ticks_per_picture_minus_1 cannot be (1 << 32) − 1. + return AOM_CODEC_UNSUP_BITSTREAM; + } + } + return AOM_CODEC_OK; +} + +static aom_codec_err_t parse_decoder_model_info( + struct aom_read_bit_buffer *rb, int *buffer_delay_length_minus_1) { + *buffer_delay_length_minus_1 = aom_rb_read_literal(rb, 5); + const uint32_t num_units_in_decoding_tick = + aom_rb_read_unsigned_literal(rb, 32); + const uint8_t buffer_removal_time_length_minus_1 = aom_rb_read_literal(rb, 5); + const uint8_t frame_presentation_time_length_minus_1 = + aom_rb_read_literal(rb, 5); + (void)num_units_in_decoding_tick; + (void)buffer_removal_time_length_minus_1; + (void)frame_presentation_time_length_minus_1; + return AOM_CODEC_OK; +} + +static aom_codec_err_t parse_op_parameters_info( + struct aom_read_bit_buffer *rb, int buffer_delay_length_minus_1) { + const int n = buffer_delay_length_minus_1 + 1; + const uint32_t decoder_buffer_delay = aom_rb_read_unsigned_literal(rb, n); + const uint32_t encoder_buffer_delay = aom_rb_read_unsigned_literal(rb, n); + const uint8_t low_delay_mode_flag = aom_rb_read_bit(rb); + (void)decoder_buffer_delay; + (void)encoder_buffer_delay; + (void)low_delay_mode_flag; + return AOM_CODEC_OK; +} + // Parses the operating points (including operating_point_idc, seq_level_idx, // and seq_tier) and then sets si->number_spatial_layers and // si->number_temporal_layers based on operating_point_idc[0]. @@ -161,10 +204,23 @@ static aom_codec_err_t parse_operating_points(struct aom_read_bit_buffer *rb, int is_reduced_header, aom_codec_stream_info_t *si) { int operating_point_idc0 = 0; - if (is_reduced_header) { aom_rb_read_literal(rb, LEVEL_BITS); // level } else { + uint8_t decoder_model_info_present_flag = 0; + int buffer_delay_length_minus_1 = 0; + aom_codec_err_t status; + const uint8_t timing_info_present_flag = aom_rb_read_bit(rb); + if (timing_info_present_flag) { + if ((status = parse_timing_info(rb)) != AOM_CODEC_OK) return status; + decoder_model_info_present_flag = aom_rb_read_bit(rb); + if (decoder_model_info_present_flag) { + if ((status = parse_decoder_model_info( + rb, &buffer_delay_length_minus_1)) != AOM_CODEC_OK) + return status; + } + } + const uint8_t initial_display_delay_present_flag = aom_rb_read_bit(rb); const uint8_t operating_points_cnt_minus_1 = aom_rb_read_literal(rb, OP_POINTS_CNT_MINUS_1_BITS); for (int i = 0; i < operating_points_cnt_minus_1 + 1; i++) { @@ -173,6 +229,20 @@ static aom_codec_err_t parse_operating_points(struct aom_read_bit_buffer *rb, if (i == 0) operating_point_idc0 = operating_point_idc; int seq_level_idx = aom_rb_read_literal(rb, LEVEL_BITS); // level if (seq_level_idx > 7) aom_rb_read_bit(rb); // tier + if (decoder_model_info_present_flag) { + const uint8_t decoder_model_present_for_this_op = aom_rb_read_bit(rb); + if (decoder_model_present_for_this_op) { + if ((status = parse_op_parameters_info( + rb, buffer_delay_length_minus_1)) != AOM_CODEC_OK) + return status; + } + } + if (initial_display_delay_present_flag) { + const uint8_t initial_display_delay_present_for_this_op = + aom_rb_read_bit(rb); + if (initial_display_delay_present_for_this_op) + aom_rb_read_literal(rb, 4); // initial_display_delay_minus_1 + } } } diff --git a/third_party/aom/av1/common/av1_inv_txfm2d.c b/third_party/aom/av1/common/av1_inv_txfm2d.c index 4f2d57b802..fc9c8d2f64 100644 --- a/third_party/aom/av1/common/av1_inv_txfm2d.c +++ b/third_party/aom/av1/common/av1_inv_txfm2d.c @@ -228,7 +228,7 @@ void av1_gen_inv_stage_range(int8_t *stage_range_col, int8_t *stage_range_row, (void)real_range_row; if (cfg->txfm_type_row == TXFM_TYPE_ADST4 && i == 1) { // the adst4 may use 1 extra bit on top of opt_range_row at stage 1 - // so opt_range_col >= real_range_col will not hold + // so opt_range_row >= real_range_row will not hold stage_range_row[i] = opt_range_row; } else { assert(opt_range_row >= real_range_row); @@ -241,7 +241,7 @@ void av1_gen_inv_stage_range(int8_t *stage_range_col, int8_t *stage_range_row, cfg->stage_range_col[i] + fwd_shift + shift[0] + bd + 1; (void)real_range_col; if (cfg->txfm_type_col == TXFM_TYPE_ADST4 && i == 1) { - // the adst4 may use 1 extra bit on top of opt_range_row at stage 1 + // the adst4 may use 1 extra bit on top of opt_range_col at stage 1 // so opt_range_col >= real_range_col will not hold stage_range_col[i] = opt_range_col; } else { diff --git a/third_party/aom/av1/common/av1_rtcd_defs.pl b/third_party/aom/av1/common/av1_rtcd_defs.pl index 7d67d37c2b..aca5ec7dea 100755 --- a/third_party/aom/av1/common/av1_rtcd_defs.pl +++ b/third_party/aom/av1/common/av1_rtcd_defs.pl @@ -111,10 +111,14 @@ specialize qw/av1_highbd_convolve8_vert/, "$sse2_x86_64"; #inv txfm add_proto qw/void av1_inv_txfm_add/, "const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param"; -specialize qw/av1_inv_txfm_add ssse3 avx2 neon/; +# TODO(http://crbug.com/aomedia/2350): avx2 is disabled due to test vector +# mismatches. +specialize qw/av1_inv_txfm_add ssse3 neon/; add_proto qw/void av1_highbd_inv_txfm_add/, "const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param"; -specialize qw/av1_highbd_inv_txfm_add sse4_1 avx2/; +# TODO(http://crbug.com/aomedia/2350): avx2 is disabled due to test vector +# mismatches. +specialize qw/av1_highbd_inv_txfm_add sse4_1/; add_proto qw/void av1_highbd_inv_txfm_add_4x4/, "const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param"; specialize qw/av1_highbd_inv_txfm_add_4x4 sse4_1/; @@ -160,8 +164,9 @@ add_proto qw/void av1_inv_txfm2d_add_32x8/, "const int32_t *input, uint16_t *out add_proto qw/void av1_highbd_dr_prediction_z1/, "uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_above, int dx, int dy, int bd"; specialize qw/av1_highbd_dr_prediction_z1 avx2/; add_proto qw/void av1_highbd_dr_prediction_z2/, "uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_above, int upsample_left, int dx, int dy, int bd"; -# TODO(https://crbug.com/aomedia/2288) -#specialize qw/av1_highbd_dr_prediction_z2 avx2/; +# TODO(niva213@gmail.com): Re-enable avx2 after fixing valgrind issue +# https://crbug.com/aomedia/2316 +# specialize qw/av1_highbd_dr_prediction_z2 avx2/; add_proto qw/void av1_highbd_dr_prediction_z3/, "uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_left, int dx, int dy, int bd"; specialize qw/av1_highbd_dr_prediction_z3 avx2/; @@ -255,18 +260,18 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/int av1_full_range_search/, "const struct macroblock *x, const struct search_site_config *cfg, MV *ref_mv, MV *best_mv, int search_param, int sad_per_bit, int *num00, const struct aom_variance_vtable *fn_ptr, const MV *center_mv"; - # TODO(yunqing): Add back the optimizations. - # add_proto qw/void av1_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count"; - # specialize qw/av1_temporal_filter_apply sse2 msa/; + add_proto qw/void av1_apply_temporal_filter/, "const uint8_t *y_frame1, int y_stride, const uint8_t *y_pred, int y_buf_stride, const uint8_t *u_frame1, const uint8_t *v_frame1, int uv_stride, const uint8_t *u_pred, const uint8_t *v_pred, int uv_buf_stride, unsigned int block_width, unsigned int block_height, int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count"; + specialize qw/av1_apply_temporal_filter sse4_1/; add_proto qw/void av1_quantize_b/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan, const qm_val_t * qm_ptr, const qm_val_t * iqm_ptr, int log_scale"; # ENCODEMB INVOKE add_proto qw/int64_t av1_highbd_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz, int bd"; - specialize qw/av1_highbd_block_error sse2/; + specialize qw/av1_highbd_block_error sse2 avx2/; - # add_proto qw/void av1_highbd_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count"; + add_proto qw/void av1_highbd_apply_temporal_filter/, "const uint8_t *yf, int y_stride, const uint8_t *yp, int y_buf_stride, const uint8_t *uf, const uint8_t *vf, int uv_stride, const uint8_t *up, const uint8_t *vp, int uv_buf_stride, unsigned int block_width, unsigned int block_height, int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count"; + specialize qw/av1_highbd_apply_temporal_filter sse4_1/; add_proto qw/void av1_highbd_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan, int log_scale"; specialize qw/av1_highbd_quantize_fp sse4_1 avx2/; diff --git a/third_party/aom/av1/common/av1_txfm.h b/third_party/aom/av1/common/av1_txfm.h index 14e2c0e9c2..20049b6806 100644 --- a/third_party/aom/av1/common/av1_txfm.h +++ b/third_party/aom/av1/common/av1_txfm.h @@ -59,7 +59,9 @@ static INLINE int32_t range_check_value(int32_t value, int8_t bit) { const int64_t min_value = -(1LL << (bit - 1)); if (value < min_value || value > max_value) { fprintf(stderr, "coeff out of bit range, value: %d bit %d\n", value, bit); +#if !CONFIG_AV1_ENCODER assert(0); +#endif } #endif // CONFIG_COEFFICIENT_RANGE_CHECKING #if DO_RANGE_CHECK_CLAMP diff --git a/third_party/aom/av1/common/blockd.h b/third_party/aom/av1/common/blockd.h index 1cb669e29b..91ef3df84b 100644 --- a/third_party/aom/av1/common/blockd.h +++ b/third_party/aom/av1/common/blockd.h @@ -190,11 +190,6 @@ typedef struct RD_STATS { int64_t ref_rdcost; int zero_rate; uint8_t invalid_rate; -#if CONFIG_ONE_PASS_SVM - int eob, eob_0, eob_1, eob_2, eob_3; - int64_t rd, rd_0, rd_1, rd_2, rd_3; - int64_t y_sse, sse_0, sse_1, sse_2, sse_3; -#endif #if CONFIG_RD_DEBUG int txb_coeff_cost[MAX_MB_PLANE]; int txb_coeff_cost_map[MAX_MB_PLANE][TXB_COEFF_COST_MAP_SIZE] diff --git a/third_party/aom/av1/common/cdef.c b/third_party/aom/av1/common/cdef.c index 556deded96..63f98832d8 100644 --- a/third_party/aom/av1/common/cdef.c +++ b/third_party/aom/av1/common/cdef.c @@ -80,7 +80,6 @@ int sb_compute_cdef_list(const AV1_COMMON *const cm, int mi_row, int mi_col, if (!is_8x8_block_skip(grid, mi_row + r, mi_col + c, cm->mi_stride)) { dlist[count].by = r >> r_shift; dlist[count].bx = c >> c_shift; - dlist[count].skip = 0; count++; } } diff --git a/third_party/aom/av1/common/cdef_block.c b/third_party/aom/av1/common/cdef_block.c index 845df377b7..dfd5882ecd 100644 --- a/third_party/aom/av1/common/cdef_block.c +++ b/third_party/aom/av1/common/cdef_block.c @@ -232,8 +232,8 @@ void cdef_filter_fb(uint8_t *dst8, uint16_t *dst16, int dstride, uint16_t *in, } for (bi = 0; bi < cdef_count; bi++) { - int t = dlist[bi].skip ? 0 : pri_strength; - int s = dlist[bi].skip ? 0 : sec_strength; + int t = pri_strength; + int s = sec_strength; by = dlist[bi].by; bx = dlist[bi].bx; if (dst8) diff --git a/third_party/aom/av1/common/cdef_block.h b/third_party/aom/av1/common/cdef_block.h index 0e921e0005..8321d48b16 100644 --- a/third_party/aom/av1/common/cdef_block.h +++ b/third_party/aom/av1/common/cdef_block.h @@ -38,7 +38,6 @@ DECLARE_ALIGNED(16, extern const int, cdef_directions[8][2]); typedef struct { uint8_t by; uint8_t bx; - uint8_t skip; } cdef_list; typedef void (*cdef_filter_block_func)(uint8_t *dst8, uint16_t *dst16, diff --git a/third_party/aom/av1/common/entropy.c b/third_party/aom/av1/common/entropy.c index 4f95ef69b0..f63ac98b76 100644 --- a/third_party/aom/av1/common/entropy.c +++ b/third_party/aom/av1/common/entropy.c @@ -101,7 +101,7 @@ void av1_reset_cdf_symbol_counters(FRAME_CONTEXT *fc) { RESET_CDF_COUNTER(fc->refmv_cdf, 2); RESET_CDF_COUNTER(fc->drl_cdf, 2); RESET_CDF_COUNTER(fc->inter_compound_mode_cdf, INTER_COMPOUND_MODES); - RESET_CDF_COUNTER(fc->compound_type_cdf, COMPOUND_TYPES - 1); + RESET_CDF_COUNTER(fc->compound_type_cdf, MASKED_COMPOUND_TYPES); RESET_CDF_COUNTER(fc->wedge_idx_cdf, 16); RESET_CDF_COUNTER(fc->interintra_cdf, 2); RESET_CDF_COUNTER(fc->wedge_interintra_cdf, 2); diff --git a/third_party/aom/av1/common/entropymode.c b/third_party/aom/av1/common/entropymode.c index 8e7e952e2c..90702ac7d2 100644 --- a/third_party/aom/av1/common/entropymode.c +++ b/third_party/aom/av1/common/entropymode.c @@ -488,17 +488,17 @@ static const aom_cdf_prob { AOM_CDF2(16384) } }; -static const aom_cdf_prob - default_compound_type_cdf[BLOCK_SIZES_ALL][CDF_SIZE(COMPOUND_TYPES - 1)] = { - { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, - { AOM_CDF2(23431) }, { AOM_CDF2(13171) }, { AOM_CDF2(11470) }, - { AOM_CDF2(9770) }, { AOM_CDF2(9100) }, { AOM_CDF2(8233) }, - { AOM_CDF2(6172) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, - { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, - { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, - { AOM_CDF2(11820) }, { AOM_CDF2(7701) }, { AOM_CDF2(16384) }, - { AOM_CDF2(16384) } - }; +static const aom_cdf_prob default_compound_type_cdf[BLOCK_SIZES_ALL][CDF_SIZE( + MASKED_COMPOUND_TYPES)] = { + { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, + { AOM_CDF2(23431) }, { AOM_CDF2(13171) }, { AOM_CDF2(11470) }, + { AOM_CDF2(9770) }, { AOM_CDF2(9100) }, { AOM_CDF2(8233) }, + { AOM_CDF2(6172) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, + { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, + { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) }, + { AOM_CDF2(11820) }, { AOM_CDF2(7701) }, { AOM_CDF2(16384) }, + { AOM_CDF2(16384) } +}; static const aom_cdf_prob default_wedge_idx_cdf[BLOCK_SIZES_ALL][CDF_SIZE(16)] = { { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432, diff --git a/third_party/aom/av1/common/entropymode.h b/third_party/aom/av1/common/entropymode.h index 7047f34d2b..69b5218499 100644 --- a/third_party/aom/av1/common/entropymode.h +++ b/third_party/aom/av1/common/entropymode.h @@ -92,7 +92,8 @@ typedef struct frame_contexts { aom_cdf_prob inter_compound_mode_cdf[INTER_MODE_CONTEXTS] [CDF_SIZE(INTER_COMPOUND_MODES)]; - aom_cdf_prob compound_type_cdf[BLOCK_SIZES_ALL][CDF_SIZE(COMPOUND_TYPES - 1)]; + aom_cdf_prob compound_type_cdf[BLOCK_SIZES_ALL] + [CDF_SIZE(MASKED_COMPOUND_TYPES)]; aom_cdf_prob wedge_idx_cdf[BLOCK_SIZES_ALL][CDF_SIZE(16)]; aom_cdf_prob interintra_cdf[BLOCK_SIZE_GROUPS][CDF_SIZE(2)]; aom_cdf_prob wedge_interintra_cdf[BLOCK_SIZES_ALL][CDF_SIZE(2)]; diff --git a/third_party/aom/av1/common/enums.h b/third_party/aom/av1/common/enums.h index 9af7b0f366..fbacc894d4 100644 --- a/third_party/aom/av1/common/enums.h +++ b/third_party/aom/av1/common/enums.h @@ -92,15 +92,6 @@ enum { MAX_PROFILES, } SENUM1BYTE(BITSTREAM_PROFILE); -#define LEVEL_MAJOR_BITS 3 -#define LEVEL_MINOR_BITS 2 -#define LEVEL_BITS (LEVEL_MAJOR_BITS + LEVEL_MINOR_BITS) - -#define LEVEL_MAJOR_MIN 2 -#define LEVEL_MAJOR_MAX ((1 << LEVEL_MAJOR_BITS) - 1 + LEVEL_MAJOR_MIN) -#define LEVEL_MINOR_MIN 0 -#define LEVEL_MINOR_MAX ((1 << LEVEL_MINOR_BITS) - 1) - #define OP_POINTS_CNT_MINUS_1_BITS 5 #define OP_POINTS_IDC_BITS 12 @@ -455,9 +446,11 @@ enum { enum { COMPOUND_AVERAGE, + COMPOUND_DISTWTD, COMPOUND_WEDGE, COMPOUND_DIFFWTD, COMPOUND_TYPES, + MASKED_COMPOUND_TYPES = 2, } UENUM1BYTE(COMPOUND_TYPE); enum { @@ -469,6 +462,37 @@ enum { FILTER_INTRA_MODES, } UENUM1BYTE(FILTER_INTRA_MODE); +enum { + SEQ_LEVEL_2_0, + SEQ_LEVEL_2_1, + SEQ_LEVEL_2_2, + SEQ_LEVEL_2_3, + SEQ_LEVEL_3_0, + SEQ_LEVEL_3_1, + SEQ_LEVEL_3_2, + SEQ_LEVEL_3_3, + SEQ_LEVEL_4_0, + SEQ_LEVEL_4_1, + SEQ_LEVEL_4_2, + SEQ_LEVEL_4_3, + SEQ_LEVEL_5_0, + SEQ_LEVEL_5_1, + SEQ_LEVEL_5_2, + SEQ_LEVEL_5_3, + SEQ_LEVEL_6_0, + SEQ_LEVEL_6_1, + SEQ_LEVEL_6_2, + SEQ_LEVEL_6_3, + SEQ_LEVEL_7_0, + SEQ_LEVEL_7_1, + SEQ_LEVEL_7_2, + SEQ_LEVEL_7_3, + SEQ_LEVELS, + SEQ_LEVEL_MAX = 31 +} UENUM1BYTE(AV1_LEVEL); + +#define LEVEL_BITS 5 + #define DIRECTIONAL_MODES 8 #define MAX_ANGLE_DELTA 3 #define ANGLE_STEP 3 diff --git a/third_party/aom/av1/common/mvref_common.c b/third_party/aom/av1/common/mvref_common.c index 3bdffe4ad4..e38891f265 100644 --- a/third_party/aom/av1/common/mvref_common.c +++ b/third_party/aom/av1/common/mvref_common.c @@ -821,7 +821,7 @@ void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd, MV_REFERENCE_FRAME rf[2]; av1_set_ref_frame(rf, ref_frame); - if (ref_frame < REF_FRAMES) { + if (global_mvs != NULL && ref_frame < REF_FRAMES) { if (ref_frame != INTRA_FRAME) { global_mvs[ref_frame] = gm_get_motion_vector( &cm->global_motion[ref_frame], cm->allow_high_precision_mv, bsize, @@ -1362,15 +1362,15 @@ static int compare_ref_frame_info(const void *arg_a, const void *arg_b) { return info_a->map_idx - info_b->map_idx; } -static void set_ref_frame_info(AV1_COMMON *const cm, int frame_idx, +static void set_ref_frame_info(int *remapped_ref_idx, int frame_idx, REF_FRAME_INFO *ref_info) { assert(frame_idx >= 0 && frame_idx < INTER_REFS_PER_FRAME); - cm->remapped_ref_idx[frame_idx] = ref_info->map_idx; + remapped_ref_idx[frame_idx] = ref_info->map_idx; } -void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, - int gld_map_idx) { +void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx, + int lst_map_idx, int gld_map_idx) { int lst_frame_sort_idx = -1; int gld_frame_sort_idx = -1; @@ -1395,8 +1395,6 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, if (buf == NULL) continue; // If this assertion fails, there is a reference leak. assert(buf->ref_count > 0); - // TODO(wtc@google.com): Remove the checking on ref_count after 2019-03-01. - if (buf->ref_count <= 0) continue; const int offset = (int)buf->order_hint; ref_frame_info[i].sort_idx = @@ -1449,7 +1447,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, // == ALTREF_FRAME == if (bwd_start_idx <= bwd_end_idx) { - set_ref_frame_info(cm, ALTREF_FRAME - LAST_FRAME, + set_ref_frame_info(remapped_ref_idx, ALTREF_FRAME - LAST_FRAME, &ref_frame_info[bwd_end_idx]); ref_flag_list[ALTREF_FRAME - LAST_FRAME] = 1; bwd_end_idx--; @@ -1457,7 +1455,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, // == BWDREF_FRAME == if (bwd_start_idx <= bwd_end_idx) { - set_ref_frame_info(cm, BWDREF_FRAME - LAST_FRAME, + set_ref_frame_info(remapped_ref_idx, BWDREF_FRAME - LAST_FRAME, &ref_frame_info[bwd_start_idx]); ref_flag_list[BWDREF_FRAME - LAST_FRAME] = 1; bwd_start_idx++; @@ -1465,7 +1463,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, // == ALTREF2_FRAME == if (bwd_start_idx <= bwd_end_idx) { - set_ref_frame_info(cm, ALTREF2_FRAME - LAST_FRAME, + set_ref_frame_info(remapped_ref_idx, ALTREF2_FRAME - LAST_FRAME, &ref_frame_info[bwd_start_idx]); ref_flag_list[ALTREF2_FRAME - LAST_FRAME] = 1; } @@ -1475,13 +1473,15 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, for (int i = fwd_start_idx; i <= fwd_end_idx; ++i) { // == LAST_FRAME == if (ref_frame_info[i].map_idx == lst_map_idx) { - set_ref_frame_info(cm, LAST_FRAME - LAST_FRAME, &ref_frame_info[i]); + set_ref_frame_info(remapped_ref_idx, LAST_FRAME - LAST_FRAME, + &ref_frame_info[i]); ref_flag_list[LAST_FRAME - LAST_FRAME] = 1; } // == GOLDEN_FRAME == if (ref_frame_info[i].map_idx == gld_map_idx) { - set_ref_frame_info(cm, GOLDEN_FRAME - LAST_FRAME, &ref_frame_info[i]); + set_ref_frame_info(remapped_ref_idx, GOLDEN_FRAME - LAST_FRAME, + &ref_frame_info[i]); ref_flag_list[GOLDEN_FRAME - LAST_FRAME] = 1; } } @@ -1513,7 +1513,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, } if (fwd_start_idx > fwd_end_idx) break; - set_ref_frame_info(cm, ref_frame - LAST_FRAME, + set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME, &ref_frame_info[fwd_end_idx]); ref_flag_list[ref_frame - LAST_FRAME] = 1; @@ -1524,7 +1524,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, for (; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) { const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx]; if (ref_flag_list[ref_frame - LAST_FRAME] == 1) continue; - set_ref_frame_info(cm, ref_frame - LAST_FRAME, + set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME, &ref_frame_info[fwd_start_idx]); ref_flag_list[ref_frame - LAST_FRAME] = 1; } diff --git a/third_party/aom/av1/common/mvref_common.h b/third_party/aom/av1/common/mvref_common.h index 1ece84a8b1..0aa9d38931 100644 --- a/third_party/aom/av1/common/mvref_common.h +++ b/third_party/aom/av1/common/mvref_common.h @@ -210,7 +210,8 @@ void av1_setup_frame_buf_refs(AV1_COMMON *cm); void av1_setup_frame_sign_bias(AV1_COMMON *cm); void av1_setup_skip_mode_allowed(AV1_COMMON *cm); void av1_setup_motion_field(AV1_COMMON *cm); -void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, int gld_map_idx); +void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx, + int lst_map_idx, int gld_map_idx); static INLINE void av1_collect_neighbors_ref_counts(MACROBLOCKD *const xd) { av1_zero(xd->neighbors_ref_counts); @@ -243,6 +244,9 @@ void av1_copy_frame_mvs(const AV1_COMMON *const cm, const MB_MODE_INFO *const mi, int mi_row, int mi_col, int x_mis, int y_mis); +// The global_mvs output parameter points to an array of REF_FRAMES elements. +// The caller may pass a null global_mvs if it does not need the global_mvs +// output. void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd, MB_MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, uint8_t ref_mv_count[MODE_CTX_REF_FRAMES], diff --git a/third_party/aom/av1/common/onyxc_int.h b/third_party/aom/av1/common/onyxc_int.h index 56f823ec92..8117dfc7cf 100644 --- a/third_party/aom/av1/common/onyxc_int.h +++ b/third_party/aom/av1/common/onyxc_int.h @@ -109,18 +109,6 @@ typedef struct { MV_REFERENCE_FRAME ref_frame; } MV_REF; -// FIXME(jack.haughton@argondesign.com): This enum was originally in -// encoder/ratectrl.h, and is encoder specific. When we move to C++, this -// should go back there and BufferPool should be templatized. -enum { - INTER_NORMAL = 0, - INTER_LOW = 1, - INTER_HIGH = 2, - GF_ARF_LOW = 3, - GF_ARF_STD = 4, - KF_STD = 5, - RATE_FACTOR_LEVELS = 6 -} UENUM1BYTE(RATE_FACTOR_LEVEL); typedef struct RefCntBuffer { // For a RefCntBuffer, the following are reference-holding variables: @@ -136,8 +124,6 @@ typedef struct RefCntBuffer { // - Total 'n' of the variables / array elements above have value 'k' (that // is, they are pointing to buffer at index 'k'). // Then, pool->frame_bufs[k].ref_count = n. - // TODO(david.turner@argondesign.com) Check whether this helpful comment is - // still correct after we finish restructuring int ref_count; unsigned int order_hint; @@ -161,6 +147,10 @@ typedef struct RefCntBuffer { hash_table hash_table; FRAME_TYPE frame_type; + // This is only used in the encoder but needs to be indexed per ref frame + // so it's extremely convenient to keep it here. + int interp_filter_selected[SWITCHABLE]; + // Inter frame reference frame delta for loop filter int8_t ref_deltas[REF_FRAMES]; @@ -168,7 +158,6 @@ typedef struct RefCntBuffer { int8_t mode_deltas[MAX_MODE_LF_DELTAS]; FRAME_CONTEXT frame_context; - RATE_FACTOR_LEVEL frame_rf_level; } RefCntBuffer; typedef struct BufferPool { @@ -193,11 +182,6 @@ typedef struct BufferPool { InternalFrameBufferList int_frame_buffers; } BufferPool; -typedef struct BitstreamLevel { - uint8_t major; - uint8_t minor; -} BitstreamLevel; - typedef struct { int cdef_pri_damping; int cdef_sec_damping; @@ -279,7 +263,7 @@ typedef struct SequenceHeader { int operating_point_idc[MAX_NUM_OPERATING_POINTS]; uint8_t display_model_info_present_flag; uint8_t decoder_model_info_present_flag; - BitstreamLevel level[MAX_NUM_OPERATING_POINTS]; + AV1_LEVEL seq_level_idx[MAX_NUM_OPERATING_POINTS]; uint8_t tier[MAX_NUM_OPERATING_POINTS]; // seq_tier in the spec. One bit: 0 // or 1. @@ -314,6 +298,7 @@ typedef struct { unsigned int frame_number; SkipModeInfo skip_mode_info; int refresh_frame_flags; // Which ref frames are overwritten by this frame + int frame_refs_short_signaling; } CurrentFrame; typedef struct AV1Common { @@ -343,9 +328,9 @@ typedef struct AV1Common { // For encoder, we have a two-level mapping from reference frame type to the // corresponding buffer in the buffer pool: - // * 'remapped_ref_idx[i - 1]' maps reference type ‘i’ (range: LAST_FRAME ... - // EXTREF_FRAME) to a remapped index ‘j’ (in range: 0 ... REF_FRAMES - 1) - // * Later, 'cm->ref_frame_map[j]' maps the remapped index ‘j’ to a pointer to + // * 'remapped_ref_idx[i - 1]' maps reference type 'i' (range: LAST_FRAME ... + // EXTREF_FRAME) to a remapped index 'j' (in range: 0 ... REF_FRAMES - 1) + // * Later, 'cm->ref_frame_map[j]' maps the remapped index 'j' to a pointer to // the reference counted buffer structure RefCntBuffer, taken from the buffer // pool cm->buffer_pool->frame_bufs. // @@ -364,10 +349,10 @@ typedef struct AV1Common { struct scale_factors ref_scale_factors[REF_FRAMES]; // For decoder, ref_frame_map[i] maps reference type 'i' to a pointer to - // the buffer in the buffer pool ‘cm->buffer_pool.frame_bufs’. + // the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'. // For encoder, ref_frame_map[j] (where j = remapped_ref_idx[i]) maps // remapped reference index 'j' (that is, original reference type 'i') to - // a pointer to the buffer in the buffer pool ‘cm->buffer_pool.frame_bufs’. + // a pointer to the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'. RefCntBuffer *ref_frame_map[REF_FRAMES]; // Prepare ref_frame_map for the next frame. @@ -517,6 +502,7 @@ typedef struct AV1Common { int tile_col_start_sb[MAX_TILE_COLS + 1]; // valid for 0 <= i <= tile_cols int tile_row_start_sb[MAX_TILE_ROWS + 1]; // valid for 0 <= i <= tile_rows int tile_width, tile_height; // In MI units + int min_inner_tile_width; // min width of non-rightmost tile unsigned int large_scale_tile; unsigned int single_tile_decoding; @@ -642,6 +628,7 @@ static INLINE RefCntBuffer *assign_cur_frame_new_fb(AV1_COMMON *const cm) { cm->cur_frame = &cm->buffer_pool->frame_bufs[new_fb_idx]; cm->cur_frame->buf.buf_8bit_valid = 0; + av1_zero(cm->cur_frame->interp_filter_selected); return cm->cur_frame; } @@ -1385,17 +1372,8 @@ static INLINE int is_coded_lossless(const AV1_COMMON *cm, return coded_lossless; } -static INLINE int is_valid_seq_level_idx(uint8_t seq_level_idx) { - return seq_level_idx < 24 || seq_level_idx == 31; -} - -static INLINE uint8_t major_minor_to_seq_level_idx(BitstreamLevel bl) { - assert(bl.major >= LEVEL_MAJOR_MIN && bl.major <= LEVEL_MAJOR_MAX); - // Since bl.minor is unsigned a comparison will return a warning: - // comparison is always true due to limited range of data type - assert(LEVEL_MINOR_MIN == 0); - assert(bl.minor <= LEVEL_MINOR_MAX); - return ((bl.major - LEVEL_MAJOR_MIN) << LEVEL_MINOR_BITS) + bl.minor; +static INLINE int is_valid_seq_level_idx(AV1_LEVEL seq_level_idx) { + return seq_level_idx < SEQ_LEVELS || seq_level_idx == SEQ_LEVEL_MAX; } #ifdef __cplusplus diff --git a/third_party/aom/av1/common/pred_common.h b/third_party/aom/av1/common/pred_common.h index 1d69ef003e..d9b30a97ad 100644 --- a/third_party/aom/av1/common/pred_common.h +++ b/third_party/aom/av1/common/pred_common.h @@ -59,9 +59,13 @@ static INLINE int av1_get_spatial_seg_pred(const AV1_COMMON *const cm, prev_l = get_segment_id(cm, cm->cur_frame->seg_map, BLOCK_4X4, mi_row - 0, mi_col - 1); } + // This property follows from the fact that get_segment_id() returns a + // nonnegative value. This allows us to test for all edge cases with a simple + // prev_ul < 0 check. + assert(IMPLIES(prev_ul >= 0, prev_u >= 0 && prev_l >= 0)); // Pick CDF index based on number of matching/out-of-bounds segment IDs. - if (prev_ul < 0 || prev_u < 0 || prev_l < 0) /* Edge case */ + if (prev_ul < 0) /* Edge cases */ *cdf_index = 0; else if ((prev_ul == prev_u) && (prev_ul == prev_l)) *cdf_index = 2; diff --git a/third_party/aom/av1/common/reconinter.h b/third_party/aom/av1/common/reconinter.h index 1385be50f9..9d562f99d2 100644 --- a/third_party/aom/av1/common/reconinter.h +++ b/third_party/aom/av1/common/reconinter.h @@ -167,6 +167,7 @@ static INLINE int is_interinter_compound_used(COMPOUND_TYPE type, const int comp_allowed = is_comp_ref_allowed(sb_type); switch (type) { case COMPOUND_AVERAGE: + case COMPOUND_DISTWTD: case COMPOUND_DIFFWTD: return comp_allowed; case COMPOUND_WEDGE: return comp_allowed && wedge_params_lookup[sb_type].bits > 0; @@ -245,13 +246,14 @@ static INLINE MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, return clamped_mv; } -static INLINE int scaled_buffer_offset(int x_offset, int y_offset, int stride, - const struct scale_factors *sf) { +static INLINE int64_t scaled_buffer_offset(int x_offset, int y_offset, + int stride, + const struct scale_factors *sf) { const int x = sf ? sf->scale_value_x(x_offset, sf) >> SCALE_EXTRA_BITS : x_offset; const int y = sf ? sf->scale_value_y(y_offset, sf) >> SCALE_EXTRA_BITS : y_offset; - return y * stride + x; + return (int64_t)y * stride + x; } static INLINE void setup_pred_plane(struct buf_2d *dst, BLOCK_SIZE bsize, diff --git a/third_party/aom/av1/common/restoration.h b/third_party/aom/av1/common/restoration.h index 5d196a9a59..6d6ba37ec7 100644 --- a/third_party/aom/av1/common/restoration.h +++ b/third_party/aom/av1/common/restoration.h @@ -22,7 +22,7 @@ extern "C" { #endif -// Boarder for Loop restoration buffer +// Border for Loop restoration buffer #define AOM_RESTORATION_FRAME_BORDER 32 #define CLIP(x, lo, hi) ((x) < (lo) ? (lo) : (x) > (hi) ? (hi) : (x)) #define RINT(x) ((x) < 0 ? (int)((x)-0.5) : (int)((x) + 0.5)) diff --git a/third_party/aom/av1/common/tile_common.c b/third_party/aom/av1/common/tile_common.c index 4d905924ac..02f50f57ed 100644 --- a/third_party/aom/av1/common/tile_common.c +++ b/third_party/aom/av1/common/tile_common.c @@ -51,6 +51,10 @@ void av1_calculate_tile_cols(AV1_COMMON *const cm) { int sb_rows = mi_rows >> cm->seq_params.mib_size_log2; int i; + // This will be overridden if there is at least two columns of tiles + // (otherwise there is no inner tile width) + cm->min_inner_tile_width = -1; + if (cm->uniform_tile_spacing_flag) { int start_sb; int size_sb = ALIGN_POWER_OF_TWO(sb_cols, cm->log2_tile_cols); @@ -67,18 +71,29 @@ void av1_calculate_tile_cols(AV1_COMMON *const cm) { cm->tile_width = size_sb << cm->seq_params.mib_size_log2; cm->tile_width = AOMMIN(cm->tile_width, cm->mi_cols); + if (cm->tile_cols > 1) { + cm->min_inner_tile_width = cm->tile_width; + } } else { int max_tile_area_sb = (sb_rows * sb_cols); int widest_tile_sb = 1; + int narrowest_inner_tile_sb = 65536; cm->log2_tile_cols = tile_log2(1, cm->tile_cols); for (i = 0; i < cm->tile_cols; i++) { int size_sb = cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i]; widest_tile_sb = AOMMAX(widest_tile_sb, size_sb); + // ignore the rightmost tile in frame for determining the narrowest + if (i < cm->tile_cols - 1) + narrowest_inner_tile_sb = AOMMIN(narrowest_inner_tile_sb, size_sb); } if (cm->min_log2_tiles) { max_tile_area_sb >>= (cm->min_log2_tiles + 1); } cm->max_tile_height_sb = AOMMAX(max_tile_area_sb / widest_tile_sb, 1); + if (cm->tile_cols > 1) { + cm->min_inner_tile_width = narrowest_inner_tile_sb + << cm->seq_params.mib_size_log2; + } } } @@ -204,3 +219,11 @@ void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { } } } + +int is_min_tile_width_satisfied(const AV1_COMMON *cm) { + // Disable check if there is a single tile col in the frame + if (cm->tile_cols == 1) return 1; + + return ((cm->min_inner_tile_width << MI_SIZE_LOG2) >= + (64 << av1_superres_scaled(cm))); +} diff --git a/third_party/aom/av1/common/tile_common.h b/third_party/aom/av1/common/tile_common.h index b7203cef75..a235f2d4c4 100644 --- a/third_party/aom/av1/common/tile_common.h +++ b/third_party/aom/av1/common/tile_common.h @@ -59,6 +59,9 @@ void av1_get_tile_limits(struct AV1Common *const cm); void av1_calculate_tile_cols(struct AV1Common *const cm); void av1_calculate_tile_rows(struct AV1Common *const cm); +// Checks if the minimum tile_width requirement is satisfied +int is_min_tile_width_satisfied(const struct AV1Common *cm); + #ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/aom/av1/common/x86/av1_inv_txfm_ssse3.c b/third_party/aom/av1/common/x86/av1_inv_txfm_ssse3.c index 9841bf3e24..de0a5617f6 100644 --- a/third_party/aom/av1/common/x86/av1_inv_txfm_ssse3.c +++ b/third_party/aom/av1/common/x86/av1_inv_txfm_ssse3.c @@ -2920,8 +2920,18 @@ void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param) { const TX_TYPE tx_type = txfm_param->tx_type; if (!txfm_param->lossless) { - av1_lowbd_inv_txfm2d_add_ssse3(dqcoeff, dst, stride, tx_type, - txfm_param->tx_size, txfm_param->eob); + switch (txfm_param->tx_size) { + case TX_4X16: + case TX_16X4: + // TODO(http://crbug.com/aomedia/2350): the ssse3 versions cause test + // vector mismatches. + av1_inv_txfm_add_c(dqcoeff, dst, stride, txfm_param); + break; + default: + av1_lowbd_inv_txfm2d_add_ssse3(dqcoeff, dst, stride, tx_type, + txfm_param->tx_size, txfm_param->eob); + break; + } } else { av1_inv_txfm_add_c(dqcoeff, dst, stride, txfm_param); } diff --git a/third_party/aom/av1/common/x86/convolve_2d_avx2.c b/third_party/aom/av1/common/x86/convolve_2d_avx2.c index 5a69ef66a1..ae12a602e0 100644 --- a/third_party/aom/av1/common/x86/convolve_2d_avx2.c +++ b/third_party/aom/av1/common/x86/convolve_2d_avx2.c @@ -27,31 +27,15 @@ void av1_convolve_2d_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, const int subpel_x_q4, const int subpel_y_q4, ConvolveParams *conv_params) { const int bd = 8; - - DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * 8]); - int im_h = h + filter_params_y->taps - 1; int im_stride = 8; - int i, j; - const int fo_vert = filter_params_y->taps / 2 - 1; - const int fo_horiz = filter_params_x->taps / 2 - 1; - const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; - + int i, is_horiz_4tap = 0, is_vert_4tap = 0; + DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * 8]); const int bits = FILTER_BITS * 2 - conv_params->round_0 - conv_params->round_1; const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; - __m256i filt[4], coeffs_h[4], coeffs_v[4]; - assert(conv_params->round_0 > 0); - filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2); - filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); - filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); - filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); - - prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_h); - prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_v); - const __m256i round_const_h = _mm256_set1_epi16( ((1 << (conv_params->round_0 - 1)) >> 1) + (1 << (bd + FILTER_BITS - 2))); const __m128i round_shift_h = _mm_cvtsi32_si128(conv_params->round_0 - 1); @@ -65,58 +49,96 @@ void av1_convolve_2d_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, ((1 << (offset_bits - conv_params->round_1)) >> 1)); const __m128i round_shift_v = _mm_cvtsi32_si128(bits); - for (j = 0; j < w; j += 8) { - for (i = 0; i < im_h; i += 2) { - __m256i data = _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); + __m256i filt[4], coeffs_h[4], coeffs_v[4]; - // Load the next line - if (i + 1 < im_h) + filt[0] = _mm256_load_si256((__m256i const *)(filt_global_avx2)); + filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); + + prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_h); + prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_v); + + // Condition for checking valid horz_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_h[0], coeffs_h[3]), 0))) + is_horiz_4tap = 1; + + // Condition for checking valid vert_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_v[0], coeffs_v[3]), 0))) + is_vert_4tap = 1; + + // horz_filt as 4 tap and vert_filt as 8 tap + if (is_horiz_4tap) { + int im_h = h + filter_params_y->taps - 1; + const int fo_vert = filter_params_y->taps / 2 - 1; + const int fo_horiz = 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; + + // horz-filter + for (int j = 0; j < w; j += 8) { + for (i = 0; i < (im_h - 2); i += 2) { + __m256i data = _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); + + // Load the next line data = _mm256_inserti128_si256( data, _mm_loadu_si128( (__m128i *)&src_ptr[(i * src_stride) + j + src_stride]), 1); + __m256i res = convolve_lowbd_x_4tap(data, coeffs_h + 1, filt); - __m256i res = convolve_lowbd_x(data, coeffs_h, filt); + res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), + round_shift_h); + _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); + } + __m256i data_1 = _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); + + __m256i res = convolve_lowbd_x_4tap(data_1, coeffs_h + 1, filt); res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); - _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); - } - /* Vertical filter */ - { + // vert filter + CONVOLVE_SR_VERTICAL_FILTER_8TAP; + } + } else if (is_vert_4tap) { + int im_h = h + 3; + const int fo_vert = 1; + const int fo_horiz = filter_params_x->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; + + filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); + filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); + + for (int j = 0; j < w; j += 8) { + // horz_filter + CONVOLVE_SR_HORIZONTAL_FILTER_8TAP; + // vert_filter + __m256i s[6]; __m256i src_0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); __m256i src_1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); __m256i src_2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); __m256i src_3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); - __m256i src_4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); - __m256i src_5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); - __m256i s[8]; s[0] = _mm256_unpacklo_epi16(src_0, src_1); s[1] = _mm256_unpacklo_epi16(src_2, src_3); - s[2] = _mm256_unpacklo_epi16(src_4, src_5); - - s[4] = _mm256_unpackhi_epi16(src_0, src_1); - s[5] = _mm256_unpackhi_epi16(src_2, src_3); - s[6] = _mm256_unpackhi_epi16(src_4, src_5); + s[3] = _mm256_unpackhi_epi16(src_0, src_1); + s[4] = _mm256_unpackhi_epi16(src_2, src_3); for (i = 0; i < h; i += 2) { const int16_t *data = &im_block[i * im_stride]; - const __m256i s6 = - _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); - const __m256i s7 = - _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); + const __m256i s4 = + _mm256_loadu_si256((__m256i *)(data + 4 * im_stride)); + const __m256i s5 = + _mm256_loadu_si256((__m256i *)(data + 5 * im_stride)); - s[3] = _mm256_unpacklo_epi16(s6, s7); - s[7] = _mm256_unpackhi_epi16(s6, s7); + s[2] = _mm256_unpacklo_epi16(s4, s5); + s[5] = _mm256_unpackhi_epi16(s4, s5); - __m256i res_a = convolve(s, coeffs_v); - __m256i res_b = convolve(s + 4, coeffs_v); + __m256i res_a = convolve_4tap(s, coeffs_v + 1); + __m256i res_b = convolve_4tap(s + 3, coeffs_v + 1); // Combine V round and 2F-H-V round into a single rounding res_a = @@ -154,13 +176,25 @@ void av1_convolve_2d_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, s[0] = s[1]; s[1] = s[2]; - s[2] = s[3]; - + s[3] = s[4]; s[4] = s[5]; - s[5] = s[6]; - s[6] = s[7]; } } + } else { + int j; + int im_h = h + filter_params_y->taps - 1; + const int fo_vert = filter_params_y->taps / 2 - 1; + const int fo_horiz = filter_params_x->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; + + filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); + filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); + + for (j = 0; j < w; j += 8) { + CONVOLVE_SR_HORIZONTAL_FILTER_8TAP; + + CONVOLVE_SR_VERTICAL_FILTER_8TAP; + } } } diff --git a/third_party/aom/av1/common/x86/convolve_avx2.c b/third_party/aom/av1/common/x86/convolve_avx2.c index 0e91ea9475..21b9fe49ce 100644 --- a/third_party/aom/av1/common/x86/convolve_avx2.c +++ b/third_party/aom/av1/common/x86/convolve_avx2.c @@ -23,153 +23,239 @@ void av1_convolve_y_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, const InterpFilterParams *filter_params_y, const int subpel_x_q4, const int subpel_y_q4, ConvolveParams *conv_params) { - int i, j; - const int fo_vert = filter_params_y->taps / 2 - 1; - const uint8_t *const src_ptr = src - fo_vert * src_stride; - + int i, j, is_vert_4tap = 0; // right shift is F-1 because we are already dividing // filter co-efficients by 2 const int right_shift_bits = (FILTER_BITS - 1); const __m128i right_shift = _mm_cvtsi32_si128(right_shift_bits); const __m256i right_shift_const = _mm256_set1_epi16((1 << right_shift_bits) >> 1); - __m256i coeffs[4], s[8]; assert(conv_params->round_0 <= FILTER_BITS); assert(((conv_params->round_0 + conv_params->round_1) <= (FILTER_BITS + 1)) || ((conv_params->round_0 + conv_params->round_1) == (2 * FILTER_BITS))); - prepare_coeffs_lowbd(filter_params_y, subpel_y_q4, coeffs); - (void)filter_params_x; (void)subpel_x_q4; (void)conv_params; + __m256i coeffs[4], s[8]; + __m128i d[6]; - for (j = 0; j < w; j += 16) { - const uint8_t *data = &src_ptr[j]; - __m256i src6; + prepare_coeffs_lowbd(filter_params_y, subpel_y_q4, coeffs); - // Load lines a and b. Line a to lower 128, line b to upper 128 - const __m256i src_01a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 0 * src_stride))), - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 1 * src_stride))), - 0x20); + // Condition for checking valid vert_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0))) + is_vert_4tap = 1; - const __m256i src_12a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 1 * src_stride))), - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 2 * src_stride))), - 0x20); + // vert_filt as 4 tap + if (is_vert_4tap) { + const int fo_vert = 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride; + for (j = 0; j < w; j += 16) { + const uint8_t *data = &src_ptr[j]; + d[0] = _mm_loadu_si128((__m128i *)(data + 0 * src_stride)); + d[1] = _mm_loadu_si128((__m128i *)(data + 1 * src_stride)); + d[2] = _mm_loadu_si128((__m128i *)(data + 2 * src_stride)); + d[3] = _mm_loadu_si128((__m128i *)(data + 3 * src_stride)); + d[4] = _mm_loadu_si128((__m128i *)(data + 4 * src_stride)); - const __m256i src_23a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 2 * src_stride))), - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 3 * src_stride))), - 0x20); + // Load lines a and b. Line a to lower 128, line b to upper 128 + const __m256i src_01a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[0]), _mm256_castsi128_si256(d[1]), 0x20); - const __m256i src_34a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 3 * src_stride))), - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 4 * src_stride))), - 0x20); + const __m256i src_12a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[1]), _mm256_castsi128_si256(d[2]), 0x20); - const __m256i src_45a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 4 * src_stride))), - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 5 * src_stride))), - 0x20); + const __m256i src_23a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[2]), _mm256_castsi128_si256(d[3]), 0x20); - src6 = _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 6 * src_stride))); - const __m256i src_56a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 5 * src_stride))), - src6, 0x20); + const __m256i src_34a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[3]), _mm256_castsi128_si256(d[4]), 0x20); - s[0] = _mm256_unpacklo_epi8(src_01a, src_12a); - s[1] = _mm256_unpacklo_epi8(src_23a, src_34a); - s[2] = _mm256_unpacklo_epi8(src_45a, src_56a); + s[0] = _mm256_unpacklo_epi8(src_01a, src_12a); + s[1] = _mm256_unpacklo_epi8(src_23a, src_34a); - s[4] = _mm256_unpackhi_epi8(src_01a, src_12a); - s[5] = _mm256_unpackhi_epi8(src_23a, src_34a); - s[6] = _mm256_unpackhi_epi8(src_45a, src_56a); + s[3] = _mm256_unpackhi_epi8(src_01a, src_12a); + s[4] = _mm256_unpackhi_epi8(src_23a, src_34a); - for (i = 0; i < h; i += 2) { - data = &src_ptr[i * src_stride + j]; - const __m256i src_67a = _mm256_permute2x128_si256( - src6, - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 7 * src_stride))), - 0x20); + for (i = 0; i < h; i += 2) { + data = &src_ptr[i * src_stride + j]; + d[5] = _mm_loadu_si128((__m128i *)(data + 5 * src_stride)); + const __m256i src_45a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[4]), _mm256_castsi128_si256(d[5]), 0x20); + + d[4] = _mm_loadu_si128((__m128i *)(data + 6 * src_stride)); + const __m256i src_56a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[5]), _mm256_castsi128_si256(d[4]), 0x20); + + s[2] = _mm256_unpacklo_epi8(src_45a, src_56a); + s[5] = _mm256_unpackhi_epi8(src_45a, src_56a); + + const __m256i res_lo = convolve_lowbd_4tap(s, coeffs + 1); + /* rounding code */ + // shift by F - 1 + const __m256i res_16b_lo = _mm256_sra_epi16( + _mm256_add_epi16(res_lo, right_shift_const), right_shift); + // 8 bit conversion and saturation to uint8 + __m256i res_8b_lo = _mm256_packus_epi16(res_16b_lo, res_16b_lo); + + if (w - j > 8) { + const __m256i res_hi = convolve_lowbd_4tap(s + 3, coeffs + 1); + + /* rounding code */ + // shift by F - 1 + const __m256i res_16b_hi = _mm256_sra_epi16( + _mm256_add_epi16(res_hi, right_shift_const), right_shift); + // 8 bit conversion and saturation to uint8 + __m256i res_8b_hi = _mm256_packus_epi16(res_16b_hi, res_16b_hi); + + __m256i res_a = _mm256_unpacklo_epi64(res_8b_lo, res_8b_hi); + + const __m128i res_0 = _mm256_castsi256_si128(res_a); + const __m128i res_1 = _mm256_extracti128_si256(res_a, 1); + + _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res_0); + _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride], + res_1); + } else { + const __m128i res_0 = _mm256_castsi256_si128(res_8b_lo); + const __m128i res_1 = _mm256_extracti128_si256(res_8b_lo, 1); + if (w - j > 4) { + _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j], res_0); + _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride], + res_1); + } else if (w - j > 2) { + xx_storel_32(&dst[i * dst_stride + j], res_0); + xx_storel_32(&dst[i * dst_stride + j + dst_stride], res_1); + } else { + __m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; + __m128i *const p_1 = + (__m128i *)&dst[i * dst_stride + j + dst_stride]; + *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); + *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); + } + } + s[0] = s[1]; + s[1] = s[2]; + + s[3] = s[4]; + s[4] = s[5]; + } + } + } else { + const int fo_vert = filter_params_y->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride; + + for (j = 0; j < w; j += 16) { + const uint8_t *data = &src_ptr[j]; + __m256i src6; + + d[0] = _mm_loadu_si128((__m128i *)(data + 0 * src_stride)); + d[1] = _mm_loadu_si128((__m128i *)(data + 1 * src_stride)); + d[2] = _mm_loadu_si128((__m128i *)(data + 2 * src_stride)); + d[3] = _mm_loadu_si128((__m128i *)(data + 3 * src_stride)); + d[4] = _mm_loadu_si128((__m128i *)(data + 4 * src_stride)); + d[5] = _mm_loadu_si128((__m128i *)(data + 5 * src_stride)); + // Load lines a and b. Line a to lower 128, line b to upper 128 + const __m256i src_01a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[0]), _mm256_castsi128_si256(d[1]), 0x20); + + const __m256i src_12a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[1]), _mm256_castsi128_si256(d[2]), 0x20); + + const __m256i src_23a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[2]), _mm256_castsi128_si256(d[3]), 0x20); + + const __m256i src_34a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[3]), _mm256_castsi128_si256(d[4]), 0x20); + + const __m256i src_45a = _mm256_permute2x128_si256( + _mm256_castsi128_si256(d[4]), _mm256_castsi128_si256(d[5]), 0x20); src6 = _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 8 * src_stride))); - const __m256i src_78a = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + 7 * src_stride))), - src6, 0x20); + _mm_loadu_si128((__m128i *)(data + 6 * src_stride))); + const __m256i src_56a = + _mm256_permute2x128_si256(_mm256_castsi128_si256(d[5]), src6, 0x20); - s[3] = _mm256_unpacklo_epi8(src_67a, src_78a); - s[7] = _mm256_unpackhi_epi8(src_67a, src_78a); + s[0] = _mm256_unpacklo_epi8(src_01a, src_12a); + s[1] = _mm256_unpacklo_epi8(src_23a, src_34a); + s[2] = _mm256_unpacklo_epi8(src_45a, src_56a); - const __m256i res_lo = convolve_lowbd(s, coeffs); + s[4] = _mm256_unpackhi_epi8(src_01a, src_12a); + s[5] = _mm256_unpackhi_epi8(src_23a, src_34a); + s[6] = _mm256_unpackhi_epi8(src_45a, src_56a); - /* rounding code */ - // shift by F - 1 - const __m256i res_16b_lo = _mm256_sra_epi16( - _mm256_add_epi16(res_lo, right_shift_const), right_shift); - // 8 bit conversion and saturation to uint8 - __m256i res_8b_lo = _mm256_packus_epi16(res_16b_lo, res_16b_lo); + for (i = 0; i < h; i += 2) { + data = &src_ptr[i * src_stride + j]; + const __m256i src_67a = _mm256_permute2x128_si256( + src6, + _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(data + 7 * src_stride))), + 0x20); - if (w - j > 8) { - const __m256i res_hi = convolve_lowbd(s + 4, coeffs); + src6 = _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(data + 8 * src_stride))); + const __m256i src_78a = _mm256_permute2x128_si256( + _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(data + 7 * src_stride))), + src6, 0x20); + + s[3] = _mm256_unpacklo_epi8(src_67a, src_78a); + s[7] = _mm256_unpackhi_epi8(src_67a, src_78a); + + const __m256i res_lo = convolve_lowbd(s, coeffs); /* rounding code */ // shift by F - 1 - const __m256i res_16b_hi = _mm256_sra_epi16( - _mm256_add_epi16(res_hi, right_shift_const), right_shift); + const __m256i res_16b_lo = _mm256_sra_epi16( + _mm256_add_epi16(res_lo, right_shift_const), right_shift); // 8 bit conversion and saturation to uint8 - __m256i res_8b_hi = _mm256_packus_epi16(res_16b_hi, res_16b_hi); + __m256i res_8b_lo = _mm256_packus_epi16(res_16b_lo, res_16b_lo); - __m256i res_a = _mm256_unpacklo_epi64(res_8b_lo, res_8b_hi); + if (w - j > 8) { + const __m256i res_hi = convolve_lowbd(s + 4, coeffs); - const __m128i res_0 = _mm256_castsi256_si128(res_a); - const __m128i res_1 = _mm256_extracti128_si256(res_a, 1); + /* rounding code */ + // shift by F - 1 + const __m256i res_16b_hi = _mm256_sra_epi16( + _mm256_add_epi16(res_hi, right_shift_const), right_shift); + // 8 bit conversion and saturation to uint8 + __m256i res_8b_hi = _mm256_packus_epi16(res_16b_hi, res_16b_hi); - _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res_0); - _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride], - res_1); - } else { - const __m128i res_0 = _mm256_castsi256_si128(res_8b_lo); - const __m128i res_1 = _mm256_extracti128_si256(res_8b_lo, 1); - if (w - j > 4) { - _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j], res_0); - _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride], + __m256i res_a = _mm256_unpacklo_epi64(res_8b_lo, res_8b_hi); + + const __m128i res_0 = _mm256_castsi256_si128(res_a); + const __m128i res_1 = _mm256_extracti128_si256(res_a, 1); + + _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res_0); + _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride], res_1); - } else if (w - j > 2) { - xx_storel_32(&dst[i * dst_stride + j], res_0); - xx_storel_32(&dst[i * dst_stride + j + dst_stride], res_1); } else { - __m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; - __m128i *const p_1 = (__m128i *)&dst[i * dst_stride + j + dst_stride]; - *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); - *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); + const __m128i res_0 = _mm256_castsi256_si128(res_8b_lo); + const __m128i res_1 = _mm256_extracti128_si256(res_8b_lo, 1); + if (w - j > 4) { + _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j], res_0); + _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride], + res_1); + } else if (w - j > 2) { + xx_storel_32(&dst[i * dst_stride + j], res_0); + xx_storel_32(&dst[i * dst_stride + j + dst_stride], res_1); + } else { + __m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; + __m128i *const p_1 = + (__m128i *)&dst[i * dst_stride + j + dst_stride]; + *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); + *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); + } } + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + + s[4] = s[5]; + s[5] = s[6]; + s[6] = s[7]; } - - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - - s[4] = s[5]; - s[5] = s[6]; - s[6] = s[7]; } } } @@ -180,26 +266,14 @@ void av1_convolve_x_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, const InterpFilterParams *filter_params_y, const int subpel_x_q4, const int subpel_y_q4, ConvolveParams *conv_params) { - int i, j; - const int fo_horiz = filter_params_x->taps / 2 - 1; - const uint8_t *const src_ptr = src - fo_horiz; const int bits = FILTER_BITS - conv_params->round_0; - __m256i filt[4], coeffs[4]; - - filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2); - filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); - filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); - filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); - - prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs); - const __m256i round_0_const = _mm256_set1_epi16((1 << (conv_params->round_0 - 1)) >> 1); const __m128i round_0_shift = _mm_cvtsi32_si128(conv_params->round_0 - 1); const __m256i round_const = _mm256_set1_epi16((1 << bits) >> 1); const __m128i round_shift = _mm_cvtsi32_si128(bits); - + int i, is_horiz_4tap = 0; (void)filter_params_y; (void)subpel_y_q4; @@ -208,51 +282,101 @@ void av1_convolve_x_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, ((conv_params->round_0 + conv_params->round_1) == 2 * FILTER_BITS)); assert(conv_params->round_0 > 0); - if (w <= 8) { - for (i = 0; i < h; i += 2) { - const __m256i data = _mm256_permute2x128_si256( - _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(&src_ptr[i * src_stride]))), - _mm256_castsi128_si256(_mm_loadu_si128( - (__m128i *)(&src_ptr[i * src_stride + src_stride]))), - 0x20); + __m256i coeffs[4], filt[4]; + filt[0] = _mm256_load_si256((__m256i const *)(filt_global_avx2)); + filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); - __m256i res_16b = convolve_lowbd_x(data, coeffs, filt); + prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs); - res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const), - round_0_shift); + // Condition for checking valid horz_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0))) + is_horiz_4tap = 1; - res_16b = - _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const), round_shift); + // horz_filt as 4 tap + if (is_horiz_4tap) { + const int fo_horiz = 1; + const uint8_t *const src_ptr = src - fo_horiz; + if (w <= 8) { + for (i = 0; i < h; i += 2) { + const __m256i data = _mm256_permute2x128_si256( + _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(&src_ptr[i * src_stride]))), + _mm256_castsi128_si256(_mm_loadu_si128( + (__m128i *)(&src_ptr[i * src_stride + src_stride]))), + 0x20); - /* rounding code */ - // 8 bit conversion and saturation to uint8 - __m256i res_8b = _mm256_packus_epi16(res_16b, res_16b); + __m256i res_16b = convolve_lowbd_x_4tap(data, coeffs + 1, filt); - const __m128i res_0 = _mm256_castsi256_si128(res_8b); - const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1); - if (w > 4) { - _mm_storel_epi64((__m128i *)&dst[i * dst_stride], res_0); - _mm_storel_epi64((__m128i *)&dst[i * dst_stride + dst_stride], res_1); - } else if (w > 2) { - xx_storel_32(&dst[i * dst_stride], res_0); - xx_storel_32(&dst[i * dst_stride + dst_stride], res_1); - } else { - __m128i *const p_0 = (__m128i *)&dst[i * dst_stride]; - __m128i *const p_1 = (__m128i *)&dst[i * dst_stride + dst_stride]; - *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); - *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); + res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const), + round_0_shift); + + res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const), + round_shift); + + /* rounding code */ + // 8 bit conversion and saturation to uint8 + __m256i res_8b = _mm256_packus_epi16(res_16b, res_16b); + + const __m128i res_0 = _mm256_castsi256_si128(res_8b); + const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1); + + if (w > 4) { + _mm_storel_epi64((__m128i *)&dst[i * dst_stride], res_0); + _mm_storel_epi64((__m128i *)&dst[i * dst_stride + dst_stride], res_1); + } else if (w > 2) { + xx_storel_32(&dst[i * dst_stride], res_0); + xx_storel_32(&dst[i * dst_stride + dst_stride], res_1); + } else { + __m128i *const p_0 = (__m128i *)&dst[i * dst_stride]; + __m128i *const p_1 = (__m128i *)&dst[i * dst_stride + dst_stride]; + *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); + *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); + } + } + } else { + for (i = 0; i < h; ++i) { + for (int j = 0; j < w; j += 16) { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 16 17 + // 18 19 20 21 22 23 + const __m256i data = _mm256_inserti128_si256( + _mm256_loadu_si256((__m256i *)&src_ptr[(i * src_stride) + j]), + _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + (j + 8)]), + 1); + + __m256i res_16b = convolve_lowbd_x_4tap(data, coeffs + 1, filt); + + res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const), + round_0_shift); + + res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const), + round_shift); + + /* rounding code */ + // 8 bit conversion and saturation to uint8 + __m256i res_8b = _mm256_packus_epi16(res_16b, res_16b); + + // Store values into the destination buffer + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + res_8b = _mm256_permute4x64_epi64(res_8b, 216); + __m128i res = _mm256_castsi256_si128(res_8b); + _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res); + } } } } else { - for (i = 0; i < h; ++i) { - for (j = 0; j < w; j += 16) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 16 17 18 - // 19 20 21 22 23 - const __m256i data = _mm256_inserti128_si256( - _mm256_loadu_si256((__m256i *)&src_ptr[(i * src_stride) + j]), - _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + (j + 8)]), - 1); + const int fo_horiz = filter_params_x->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_horiz; + filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); + filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); + + if (w <= 8) { + for (i = 0; i < h; i += 2) { + const __m256i data = _mm256_permute2x128_si256( + _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(&src_ptr[i * src_stride]))), + _mm256_castsi128_si256(_mm_loadu_si128( + (__m128i *)(&src_ptr[i * src_stride + src_stride]))), + 0x20); __m256i res_16b = convolve_lowbd_x(data, coeffs, filt); @@ -266,11 +390,49 @@ void av1_convolve_x_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst, // 8 bit conversion and saturation to uint8 __m256i res_8b = _mm256_packus_epi16(res_16b, res_16b); - // Store values into the destination buffer - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - res_8b = _mm256_permute4x64_epi64(res_8b, 216); - __m128i res = _mm256_castsi256_si128(res_8b); - _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res); + const __m128i res_0 = _mm256_castsi256_si128(res_8b); + const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1); + if (w > 4) { + _mm_storel_epi64((__m128i *)&dst[i * dst_stride], res_0); + _mm_storel_epi64((__m128i *)&dst[i * dst_stride + dst_stride], res_1); + } else if (w > 2) { + xx_storel_32(&dst[i * dst_stride], res_0); + xx_storel_32(&dst[i * dst_stride + dst_stride], res_1); + } else { + __m128i *const p_0 = (__m128i *)&dst[i * dst_stride]; + __m128i *const p_1 = (__m128i *)&dst[i * dst_stride + dst_stride]; + *(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); + *(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); + } + } + } else { + for (i = 0; i < h; ++i) { + for (int j = 0; j < w; j += 16) { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 16 17 + // 18 19 20 21 22 23 + const __m256i data = _mm256_inserti128_si256( + _mm256_loadu_si256((__m256i *)&src_ptr[(i * src_stride) + j]), + _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + (j + 8)]), + 1); + + __m256i res_16b = convolve_lowbd_x(data, coeffs, filt); + + res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const), + round_0_shift); + + res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const), + round_shift); + + /* rounding code */ + // 8 bit conversion and saturation to uint8 + __m256i res_8b = _mm256_packus_epi16(res_16b, res_16b); + + // Store values into the destination buffer + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + res_8b = _mm256_permute4x64_epi64(res_8b, 216); + __m128i res = _mm256_castsi256_si128(res_8b); + _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res); + } } } } diff --git a/third_party/aom/av1/common/x86/highbd_inv_txfm_sse4.c b/third_party/aom/av1/common/x86/highbd_inv_txfm_sse4.c index 2f0eecb8bc..8a8641d829 100644 --- a/third_party/aom/av1/common/x86/highbd_inv_txfm_sse4.c +++ b/third_party/aom/av1/common/x86/highbd_inv_txfm_sse4.c @@ -5926,28 +5926,16 @@ void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *input, uint8_t *dest, assert(av1_ext_tx_used[txfm_param->tx_set_type][txfm_param->tx_type]); const TX_SIZE tx_size = txfm_param->tx_size; switch (tx_size) { - case TX_8X8: - av1_highbd_inv_txfm_add_8x8_sse4_1(input, dest, stride, txfm_param); - break; case TX_4X8: av1_highbd_inv_txfm_add_4x8_sse4_1(input, dest, stride, txfm_param); break; case TX_8X4: av1_highbd_inv_txfm_add_8x4_sse4_1(input, dest, stride, txfm_param); break; - case TX_4X4: - av1_highbd_inv_txfm_add_4x4_sse4_1(input, dest, stride, txfm_param); - break; - case TX_16X4: - av1_highbd_inv_txfm_add_16x4_sse4_1(input, dest, stride, txfm_param); - break; - case TX_4X16: - av1_highbd_inv_txfm_add_4x16_sse4_1(input, dest, stride, txfm_param); - break; default: - av1_highbd_inv_txfm2d_add_universe_sse4_1( - input, dest, stride, txfm_param->tx_type, tx_size, txfm_param->eob, - txfm_param->bd); + // TODO(http://crbug.com/aomedia/2350): the remaining sse4_1 versions + // cause test vector mismatches. + av1_highbd_inv_txfm_add_c(input, dest, stride, txfm_param); break; } } diff --git a/third_party/aom/av1/common/x86/jnt_convolve_avx2.c b/third_party/aom/av1/common/x86/jnt_convolve_avx2.c index cc46ef35bc..23cd6abbea 100644 --- a/third_party/aom/av1/common/x86/jnt_convolve_avx2.c +++ b/third_party/aom/av1/common/x86/jnt_convolve_avx2.c @@ -44,9 +44,7 @@ void av1_dist_wtd_convolve_x_avx2(const uint8_t *src, int src_stride, CONV_BUF_TYPE *dst = conv_params->dst; int dst_stride = conv_params->dst_stride; const int bd = 8; - int i, j; - const int fo_horiz = filter_params_x->taps / 2 - 1; - const uint8_t *const src_ptr = src - fo_horiz; + int i, j, is_horiz_4tap = 0; const int bits = FILTER_BITS - conv_params->round_1; const __m256i wt = unpack_weights_avx2(conv_params); const int do_average = conv_params->do_average; @@ -58,18 +56,10 @@ void av1_dist_wtd_convolve_x_avx2(const uint8_t *src, int src_stride, const int rounding_shift = 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; const __m256i rounding_const = _mm256_set1_epi16((1 << rounding_shift) >> 1); - __m256i filt[4], coeffs[4]; assert(bits >= 0); assert(conv_params->round_0 > 0); - filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2); - filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); - filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); - filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); - - prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs); - const __m256i round_const = _mm256_set1_epi16((1 << (conv_params->round_0 - 1)) >> 1); const __m128i round_shift = _mm_cvtsi32_si128(conv_params->round_0 - 1); @@ -77,51 +67,121 @@ void av1_dist_wtd_convolve_x_avx2(const uint8_t *src, int src_stride, (void)filter_params_y; (void)subpel_y_q4; - for (i = 0; i < h; i += 2) { - const uint8_t *src_data = src_ptr + i * src_stride; - CONV_BUF_TYPE *dst_data = dst + i * dst_stride; - for (j = 0; j < w; j += 8) { - const __m256i data = - load_line2_avx2(&src_data[j], &src_data[j + src_stride]); + __m256i filt[4], coeffs[4]; - __m256i res = convolve_lowbd_x(data, coeffs, filt); + filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2); + filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); - res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const), round_shift); + prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs); - res = _mm256_slli_epi16(res, bits); + // Condition for checking valid horz_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0))) + is_horiz_4tap = 1; - const __m256i res_unsigned = _mm256_add_epi16(res, offset_const); + // horz_filt as 4 tap + if (is_horiz_4tap) { + const int fo_horiz = 1; + const uint8_t *const src_ptr = src - fo_horiz; + for (i = 0; i < h; i += 2) { + const uint8_t *src_data = src_ptr + i * src_stride; + CONV_BUF_TYPE *dst_data = dst + i * dst_stride; + for (j = 0; j < w; j += 8) { + const __m256i data = + load_line2_avx2(&src_data[j], &src_data[j + src_stride]); - // Accumulate values into the destination buffer - if (do_average) { - const __m256i data_ref_0 = - load_line2_avx2(&dst_data[j], &dst_data[j + dst_stride]); - const __m256i comp_avg_res = - comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); + __m256i res = convolve_lowbd_x_4tap(data, coeffs + 1, filt); + res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const), round_shift); + res = _mm256_slli_epi16(res, bits); - const __m256i round_result = convolve_rounding( - &comp_avg_res, &offset_const, &rounding_const, rounding_shift); + const __m256i res_unsigned = _mm256_add_epi16(res, offset_const); - const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); - const __m128i res_0 = _mm256_castsi256_si128(res_8); - const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + // Accumulate values into the destination buffer + if (do_average) { + const __m256i data_ref_0 = + load_line2_avx2(&dst_data[j], &dst_data[j + dst_stride]); + const __m256i comp_avg_res = + comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); - if (w > 4) { - _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); - _mm_storel_epi64( - (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); + const __m256i round_result = convolve_rounding( + &comp_avg_res, &offset_const, &rounding_const, rounding_shift); + + const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); + const __m128i res_0 = _mm256_castsi256_si128(res_8); + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + + if (w > 4) { + _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); + _mm_storel_epi64( + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); + } else { + *(uint32_t *)(&dst0[i * dst_stride0 + j]) = + _mm_cvtsi128_si32(res_0); + *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = + _mm_cvtsi128_si32(res_1); + } } else { - *(uint32_t *)(&dst0[i * dst_stride0 + j]) = _mm_cvtsi128_si32(res_0); - *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = - _mm_cvtsi128_si32(res_1); - } - } else { - const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); + const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); - const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), - res_1); + const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), + res_1); + } + } + } + } else { + const int fo_horiz = filter_params_x->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_horiz; + + filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); + filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); + for (i = 0; i < h; i += 2) { + const uint8_t *src_data = src_ptr + i * src_stride; + CONV_BUF_TYPE *dst_data = dst + i * dst_stride; + for (j = 0; j < w; j += 8) { + const __m256i data = + load_line2_avx2(&src_data[j], &src_data[j + src_stride]); + + __m256i res = convolve_lowbd_x(data, coeffs, filt); + + res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const), round_shift); + + res = _mm256_slli_epi16(res, bits); + + const __m256i res_unsigned = _mm256_add_epi16(res, offset_const); + + // Accumulate values into the destination buffer + if (do_average) { + const __m256i data_ref_0 = + load_line2_avx2(&dst_data[j], &dst_data[j + dst_stride]); + const __m256i comp_avg_res = + comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); + + const __m256i round_result = convolve_rounding( + &comp_avg_res, &offset_const, &rounding_const, rounding_shift); + + const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); + const __m128i res_0 = _mm256_castsi256_si128(res_8); + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + + if (w > 4) { + _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); + _mm_storel_epi64( + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); + } else { + *(uint32_t *)(&dst0[i * dst_stride0 + j]) = + _mm_cvtsi128_si32(res_0); + *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = + _mm_cvtsi128_si32(res_1); + } + } else { + const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); + + const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), + res_1); + } } } } @@ -136,9 +196,7 @@ void av1_dist_wtd_convolve_y_avx2(const uint8_t *src, int src_stride, CONV_BUF_TYPE *dst = conv_params->dst; int dst_stride = conv_params->dst_stride; const int bd = 8; - int i, j; - const int fo_vert = filter_params_y->taps / 2 - 1; - const uint8_t *const src_ptr = src - fo_vert * src_stride; + int i, j, is_vert_4tap = 0; // +1 to compensate for dividing the filter coeffs by 2 const int left_shift = FILTER_BITS - conv_params->round_0 + 1; const __m256i round_const = @@ -168,171 +226,368 @@ void av1_dist_wtd_convolve_y_avx2(const uint8_t *src, int src_stride, (void)filter_params_x; (void)subpel_x_q4; - for (j = 0; j < w; j += 16) { - const uint8_t *data = &src_ptr[j]; - __m256i src6; - // Load lines a and b. Line a to lower 128, line b to upper 128 - { - __m256i src_ab[7]; - __m256i src_a[7]; - src_a[0] = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); - for (int kk = 0; kk < 6; ++kk) { - data += src_stride; - src_a[kk + 1] = - _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); - src_ab[kk] = _mm256_permute2x128_si256(src_a[kk], src_a[kk + 1], 0x20); + // Condition for checking valid vert_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0))) + is_vert_4tap = 1; + + if (is_vert_4tap) { + const int fo_vert = 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride; + for (j = 0; j < w; j += 16) { + const uint8_t *data = &src_ptr[j]; + __m256i src4; + // Load lines a and b. Line a to lower 128, line b to upper 128 + { + __m256i src_ab[4]; + __m256i src_a[5]; + src_a[0] = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); + for (int kk = 0; kk < 4; ++kk) { + data += src_stride; + src_a[kk + 1] = + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); + src_ab[kk] = + _mm256_permute2x128_si256(src_a[kk], src_a[kk + 1], 0x20); + } + src4 = src_a[4]; + s[0] = _mm256_unpacklo_epi8(src_ab[0], src_ab[1]); + s[1] = _mm256_unpacklo_epi8(src_ab[2], src_ab[3]); + + s[3] = _mm256_unpackhi_epi8(src_ab[0], src_ab[1]); + s[4] = _mm256_unpackhi_epi8(src_ab[2], src_ab[3]); } - src6 = src_a[6]; - s[0] = _mm256_unpacklo_epi8(src_ab[0], src_ab[1]); - s[1] = _mm256_unpacklo_epi8(src_ab[2], src_ab[3]); - s[2] = _mm256_unpacklo_epi8(src_ab[4], src_ab[5]); - s[4] = _mm256_unpackhi_epi8(src_ab[0], src_ab[1]); - s[5] = _mm256_unpackhi_epi8(src_ab[2], src_ab[3]); - s[6] = _mm256_unpackhi_epi8(src_ab[4], src_ab[5]); - } - for (i = 0; i < h; i += 2) { - data = &src_ptr[(i + 7) * src_stride + j]; - const __m256i src7 = - _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); - const __m256i src_67a = _mm256_permute2x128_si256(src6, src7, 0x20); + for (i = 0; i < h; i += 2) { + data = &src_ptr[(i + 5) * src_stride + j]; + const __m256i src5 = + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); + const __m256i src_45a = _mm256_permute2x128_si256(src4, src5, 0x20); - src6 = _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)(data + src_stride))); - const __m256i src_78a = _mm256_permute2x128_si256(src7, src6, 0x20); + src4 = _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(data + src_stride))); + const __m256i src_56a = _mm256_permute2x128_si256(src5, src4, 0x20); - s[3] = _mm256_unpacklo_epi8(src_67a, src_78a); - s[7] = _mm256_unpackhi_epi8(src_67a, src_78a); + s[2] = _mm256_unpacklo_epi8(src_45a, src_56a); + s[5] = _mm256_unpackhi_epi8(src_45a, src_56a); - __m256i res_lo = convolve_lowbd(s, coeffs); + __m256i res_lo = convolve_lowbd_4tap(s, coeffs + 1); - res_lo = _mm256_add_epi16(res_lo, offset_const_1); + res_lo = _mm256_add_epi16(res_lo, offset_const_1); - const __m256i res_lo_0_32b = _mm256_unpacklo_epi16(res_lo, zero); - const __m256i res_lo_0_shift = - _mm256_slli_epi32(res_lo_0_32b, left_shift); - const __m256i res_lo_0_round = _mm256_sra_epi32( - _mm256_add_epi32(res_lo_0_shift, round_const), round_shift); + const __m256i res_lo_0_32b = _mm256_unpacklo_epi16(res_lo, zero); + const __m256i res_lo_0_shift = + _mm256_slli_epi32(res_lo_0_32b, left_shift); + const __m256i res_lo_0_round = _mm256_sra_epi32( + _mm256_add_epi32(res_lo_0_shift, round_const), round_shift); - const __m256i res_lo_1_32b = _mm256_unpackhi_epi16(res_lo, zero); - const __m256i res_lo_1_shift = - _mm256_slli_epi32(res_lo_1_32b, left_shift); - const __m256i res_lo_1_round = _mm256_sra_epi32( - _mm256_add_epi32(res_lo_1_shift, round_const), round_shift); + const __m256i res_lo_1_32b = _mm256_unpackhi_epi16(res_lo, zero); + const __m256i res_lo_1_shift = + _mm256_slli_epi32(res_lo_1_32b, left_shift); + const __m256i res_lo_1_round = _mm256_sra_epi32( + _mm256_add_epi32(res_lo_1_shift, round_const), round_shift); - const __m256i res_lo_round = - _mm256_packs_epi32(res_lo_0_round, res_lo_1_round); + const __m256i res_lo_round = + _mm256_packs_epi32(res_lo_0_round, res_lo_1_round); - const __m256i res_lo_unsigned = - _mm256_add_epi16(res_lo_round, offset_const_2); + const __m256i res_lo_unsigned = + _mm256_add_epi16(res_lo_round, offset_const_2); - if (w - j < 16) { - if (do_average) { - const __m256i data_ref_0 = load_line2_avx2( - &dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]); - const __m256i comp_avg_res = comp_avg(&data_ref_0, &res_lo_unsigned, - &wt, use_dist_wtd_comp_avg); + if (w - j < 16) { + if (do_average) { + const __m256i data_ref_0 = + load_line2_avx2(&dst[i * dst_stride + j], + &dst[i * dst_stride + j + dst_stride]); + const __m256i comp_avg_res = comp_avg(&data_ref_0, &res_lo_unsigned, + &wt, use_dist_wtd_comp_avg); - const __m256i round_result = convolve_rounding( - &comp_avg_res, &offset_const, &rounding_const, rounding_shift); + const __m256i round_result = convolve_rounding( + &comp_avg_res, &offset_const, &rounding_const, rounding_shift); - const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); - const __m128i res_0 = _mm256_castsi256_si128(res_8); - const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + const __m256i res_8 = + _mm256_packus_epi16(round_result, round_result); + const __m128i res_0 = _mm256_castsi256_si128(res_8); + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); - if (w - j > 4) { - _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); - _mm_storel_epi64( - (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); + if (w - j > 4) { + _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); + _mm_storel_epi64( + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), + res_1); + } else { + *(uint32_t *)(&dst0[i * dst_stride0 + j]) = + _mm_cvtsi128_si32(res_0); + *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = + _mm_cvtsi128_si32(res_1); + } } else { - *(uint32_t *)(&dst0[i * dst_stride0 + j]) = - _mm_cvtsi128_si32(res_0); - *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = - _mm_cvtsi128_si32(res_1); + const __m128i res_0 = _mm256_castsi256_si128(res_lo_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); + + const __m128i res_1 = _mm256_extracti128_si256(res_lo_unsigned, 1); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), + res_1); } } else { - const __m128i res_0 = _mm256_castsi256_si128(res_lo_unsigned); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); + __m256i res_hi = convolve_lowbd_4tap(s + 3, coeffs + 1); - const __m128i res_1 = _mm256_extracti128_si256(res_lo_unsigned, 1); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), - res_1); + res_hi = _mm256_add_epi16(res_hi, offset_const_1); + + const __m256i res_hi_0_32b = _mm256_unpacklo_epi16(res_hi, zero); + const __m256i res_hi_0_shift = + _mm256_slli_epi32(res_hi_0_32b, left_shift); + const __m256i res_hi_0_round = _mm256_sra_epi32( + _mm256_add_epi32(res_hi_0_shift, round_const), round_shift); + + const __m256i res_hi_1_32b = _mm256_unpackhi_epi16(res_hi, zero); + const __m256i res_hi_1_shift = + _mm256_slli_epi32(res_hi_1_32b, left_shift); + const __m256i res_hi_1_round = _mm256_sra_epi32( + _mm256_add_epi32(res_hi_1_shift, round_const), round_shift); + + const __m256i res_hi_round = + _mm256_packs_epi32(res_hi_0_round, res_hi_1_round); + + const __m256i res_hi_unsigned = + _mm256_add_epi16(res_hi_round, offset_const_2); + + if (do_average) { + const __m256i data_ref_0_lo = + load_line2_avx2(&dst[i * dst_stride + j], + &dst[i * dst_stride + j + dst_stride]); + + const __m256i data_ref_0_hi = + load_line2_avx2(&dst[i * dst_stride + j + 8], + &dst[i * dst_stride + j + 8 + dst_stride]); + + const __m256i comp_avg_res_lo = comp_avg( + &data_ref_0_lo, &res_lo_unsigned, &wt, use_dist_wtd_comp_avg); + + const __m256i comp_avg_res_hi = comp_avg( + &data_ref_0_hi, &res_hi_unsigned, &wt, use_dist_wtd_comp_avg); + + const __m256i round_result_lo = + convolve_rounding(&comp_avg_res_lo, &offset_const, + &rounding_const, rounding_shift); + + const __m256i round_result_hi = + convolve_rounding(&comp_avg_res_hi, &offset_const, + &rounding_const, rounding_shift); + + const __m256i res_8 = + _mm256_packus_epi16(round_result_lo, round_result_hi); + const __m128i res_0 = _mm256_castsi256_si128(res_8); + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + + _mm_store_si128((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); + _mm_store_si128( + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); + + } else { + const __m128i res_lo_0 = _mm256_castsi256_si128(res_lo_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_lo_0); + + const __m128i res_lo_1 = + _mm256_extracti128_si256(res_lo_unsigned, 1); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), + res_lo_1); + + const __m128i res_hi_0 = _mm256_castsi256_si128(res_hi_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + 8]), + res_hi_0); + + const __m128i res_hi_1 = + _mm256_extracti128_si256(res_hi_unsigned, 1); + _mm_store_si128( + (__m128i *)(&dst[i * dst_stride + j + 8 + dst_stride]), + res_hi_1); + } } - } else { - __m256i res_hi = convolve_lowbd(s + 4, coeffs); + s[0] = s[1]; + s[1] = s[2]; - res_hi = _mm256_add_epi16(res_hi, offset_const_1); - - const __m256i res_hi_0_32b = _mm256_unpacklo_epi16(res_hi, zero); - const __m256i res_hi_0_shift = - _mm256_slli_epi32(res_hi_0_32b, left_shift); - const __m256i res_hi_0_round = _mm256_sra_epi32( - _mm256_add_epi32(res_hi_0_shift, round_const), round_shift); - - const __m256i res_hi_1_32b = _mm256_unpackhi_epi16(res_hi, zero); - const __m256i res_hi_1_shift = - _mm256_slli_epi32(res_hi_1_32b, left_shift); - const __m256i res_hi_1_round = _mm256_sra_epi32( - _mm256_add_epi32(res_hi_1_shift, round_const), round_shift); - - const __m256i res_hi_round = - _mm256_packs_epi32(res_hi_0_round, res_hi_1_round); - - const __m256i res_hi_unsigned = - _mm256_add_epi16(res_hi_round, offset_const_2); - - if (do_average) { - const __m256i data_ref_0_lo = load_line2_avx2( - &dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]); - - const __m256i data_ref_0_hi = - load_line2_avx2(&dst[i * dst_stride + j + 8], - &dst[i * dst_stride + j + 8 + dst_stride]); - - const __m256i comp_avg_res_lo = comp_avg( - &data_ref_0_lo, &res_lo_unsigned, &wt, use_dist_wtd_comp_avg); - - const __m256i comp_avg_res_hi = comp_avg( - &data_ref_0_hi, &res_hi_unsigned, &wt, use_dist_wtd_comp_avg); - - const __m256i round_result_lo = convolve_rounding( - &comp_avg_res_lo, &offset_const, &rounding_const, rounding_shift); - - const __m256i round_result_hi = convolve_rounding( - &comp_avg_res_hi, &offset_const, &rounding_const, rounding_shift); - - const __m256i res_8 = - _mm256_packus_epi16(round_result_lo, round_result_hi); - const __m128i res_0 = _mm256_castsi256_si128(res_8); - const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); - - _mm_store_si128((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); - _mm_store_si128( - (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); - - } else { - const __m128i res_lo_0 = _mm256_castsi256_si128(res_lo_unsigned); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_lo_0); - - const __m128i res_lo_1 = _mm256_extracti128_si256(res_lo_unsigned, 1); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), - res_lo_1); - - const __m128i res_hi_0 = _mm256_castsi256_si128(res_hi_unsigned); - _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + 8]), res_hi_0); - - const __m128i res_hi_1 = _mm256_extracti128_si256(res_hi_unsigned, 1); - _mm_store_si128( - (__m128i *)(&dst[i * dst_stride + j + 8 + dst_stride]), res_hi_1); - } + s[3] = s[4]; + s[4] = s[5]; + } + } + } else { + const int fo_vert = filter_params_y->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride; + for (j = 0; j < w; j += 16) { + const uint8_t *data = &src_ptr[j]; + __m256i src6; + // Load lines a and b. Line a to lower 128, line b to upper 128 + { + __m256i src_ab[7]; + __m256i src_a[7]; + src_a[0] = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); + for (int kk = 0; kk < 6; ++kk) { + data += src_stride; + src_a[kk + 1] = + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); + src_ab[kk] = + _mm256_permute2x128_si256(src_a[kk], src_a[kk + 1], 0x20); + } + src6 = src_a[6]; + s[0] = _mm256_unpacklo_epi8(src_ab[0], src_ab[1]); + s[1] = _mm256_unpacklo_epi8(src_ab[2], src_ab[3]); + s[2] = _mm256_unpacklo_epi8(src_ab[4], src_ab[5]); + s[4] = _mm256_unpackhi_epi8(src_ab[0], src_ab[1]); + s[5] = _mm256_unpackhi_epi8(src_ab[2], src_ab[3]); + s[6] = _mm256_unpackhi_epi8(src_ab[4], src_ab[5]); } - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - s[4] = s[5]; - s[5] = s[6]; - s[6] = s[7]; + for (i = 0; i < h; i += 2) { + data = &src_ptr[(i + 7) * src_stride + j]; + const __m256i src7 = + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data)); + const __m256i src_67a = _mm256_permute2x128_si256(src6, src7, 0x20); + + src6 = _mm256_castsi128_si256( + _mm_loadu_si128((__m128i *)(data + src_stride))); + const __m256i src_78a = _mm256_permute2x128_si256(src7, src6, 0x20); + + s[3] = _mm256_unpacklo_epi8(src_67a, src_78a); + s[7] = _mm256_unpackhi_epi8(src_67a, src_78a); + + __m256i res_lo = convolve_lowbd(s, coeffs); + + res_lo = _mm256_add_epi16(res_lo, offset_const_1); + + const __m256i res_lo_0_32b = _mm256_unpacklo_epi16(res_lo, zero); + const __m256i res_lo_0_shift = + _mm256_slli_epi32(res_lo_0_32b, left_shift); + const __m256i res_lo_0_round = _mm256_sra_epi32( + _mm256_add_epi32(res_lo_0_shift, round_const), round_shift); + + const __m256i res_lo_1_32b = _mm256_unpackhi_epi16(res_lo, zero); + const __m256i res_lo_1_shift = + _mm256_slli_epi32(res_lo_1_32b, left_shift); + const __m256i res_lo_1_round = _mm256_sra_epi32( + _mm256_add_epi32(res_lo_1_shift, round_const), round_shift); + + const __m256i res_lo_round = + _mm256_packs_epi32(res_lo_0_round, res_lo_1_round); + + const __m256i res_lo_unsigned = + _mm256_add_epi16(res_lo_round, offset_const_2); + + if (w - j < 16) { + if (do_average) { + const __m256i data_ref_0 = + load_line2_avx2(&dst[i * dst_stride + j], + &dst[i * dst_stride + j + dst_stride]); + const __m256i comp_avg_res = comp_avg(&data_ref_0, &res_lo_unsigned, + &wt, use_dist_wtd_comp_avg); + + const __m256i round_result = convolve_rounding( + &comp_avg_res, &offset_const, &rounding_const, rounding_shift); + + const __m256i res_8 = + _mm256_packus_epi16(round_result, round_result); + const __m128i res_0 = _mm256_castsi256_si128(res_8); + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + + if (w - j > 4) { + _mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); + _mm_storel_epi64( + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), + res_1); + } else { + *(uint32_t *)(&dst0[i * dst_stride0 + j]) = + _mm_cvtsi128_si32(res_0); + *(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = + _mm_cvtsi128_si32(res_1); + } + } else { + const __m128i res_0 = _mm256_castsi256_si128(res_lo_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); + + const __m128i res_1 = _mm256_extracti128_si256(res_lo_unsigned, 1); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), + res_1); + } + } else { + __m256i res_hi = convolve_lowbd(s + 4, coeffs); + + res_hi = _mm256_add_epi16(res_hi, offset_const_1); + + const __m256i res_hi_0_32b = _mm256_unpacklo_epi16(res_hi, zero); + const __m256i res_hi_0_shift = + _mm256_slli_epi32(res_hi_0_32b, left_shift); + const __m256i res_hi_0_round = _mm256_sra_epi32( + _mm256_add_epi32(res_hi_0_shift, round_const), round_shift); + + const __m256i res_hi_1_32b = _mm256_unpackhi_epi16(res_hi, zero); + const __m256i res_hi_1_shift = + _mm256_slli_epi32(res_hi_1_32b, left_shift); + const __m256i res_hi_1_round = _mm256_sra_epi32( + _mm256_add_epi32(res_hi_1_shift, round_const), round_shift); + + const __m256i res_hi_round = + _mm256_packs_epi32(res_hi_0_round, res_hi_1_round); + + const __m256i res_hi_unsigned = + _mm256_add_epi16(res_hi_round, offset_const_2); + + if (do_average) { + const __m256i data_ref_0_lo = + load_line2_avx2(&dst[i * dst_stride + j], + &dst[i * dst_stride + j + dst_stride]); + + const __m256i data_ref_0_hi = + load_line2_avx2(&dst[i * dst_stride + j + 8], + &dst[i * dst_stride + j + 8 + dst_stride]); + + const __m256i comp_avg_res_lo = comp_avg( + &data_ref_0_lo, &res_lo_unsigned, &wt, use_dist_wtd_comp_avg); + + const __m256i comp_avg_res_hi = comp_avg( + &data_ref_0_hi, &res_hi_unsigned, &wt, use_dist_wtd_comp_avg); + + const __m256i round_result_lo = + convolve_rounding(&comp_avg_res_lo, &offset_const, + &rounding_const, rounding_shift); + + const __m256i round_result_hi = + convolve_rounding(&comp_avg_res_hi, &offset_const, + &rounding_const, rounding_shift); + + const __m256i res_8 = + _mm256_packus_epi16(round_result_lo, round_result_hi); + const __m128i res_0 = _mm256_castsi256_si128(res_8); + const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); + + _mm_store_si128((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); + _mm_store_si128( + (__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); + + } else { + const __m128i res_lo_0 = _mm256_castsi256_si128(res_lo_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_lo_0); + + const __m128i res_lo_1 = + _mm256_extracti128_si256(res_lo_unsigned, 1); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), + res_lo_1); + + const __m128i res_hi_0 = _mm256_castsi256_si128(res_hi_unsigned); + _mm_store_si128((__m128i *)(&dst[i * dst_stride + j + 8]), + res_hi_0); + + const __m128i res_hi_1 = + _mm256_extracti128_si256(res_hi_unsigned, 1); + _mm_store_si128( + (__m128i *)(&dst[i * dst_stride + j + 8 + dst_stride]), + res_hi_1); + } + } + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + + s[4] = s[5]; + s[5] = s[6]; + s[6] = s[7]; + } } } } @@ -348,12 +603,9 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride, const int bd = 8; DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * 8]); - int im_h = h + filter_params_y->taps - 1; + int im_stride = 8; - int i, j; - const int fo_vert = filter_params_y->taps / 2 - 1; - const int fo_horiz = filter_params_x->taps / 2 - 1; - const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; + int i, is_horiz_4tap = 0, is_vert_4tap = 0; const __m256i wt = unpack_weights_avx2(conv_params); const int do_average = conv_params->do_average; const int use_dist_wtd_comp_avg = conv_params->use_dist_wtd_comp_avg; @@ -364,18 +616,9 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride, const int rounding_shift = 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1; const __m256i rounding_const = _mm256_set1_epi16((1 << rounding_shift) >> 1); - __m256i filt[4], s[8], coeffs_x[4], coeffs_y[4]; assert(conv_params->round_0 > 0); - filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2); - filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); - filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); - filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); - - prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_x); - prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_y); - const __m256i round_const_h = _mm256_set1_epi16( ((1 << (conv_params->round_0 - 1)) >> 1) + (1 << (bd + FILTER_BITS - 2))); const __m128i round_shift_h = _mm_cvtsi32_si128(conv_params->round_0 - 1); @@ -385,9 +628,29 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride, (1 << (bd + 2 * FILTER_BITS - conv_params->round_0 - 1))); const __m128i round_shift_v = _mm_cvtsi32_si128(conv_params->round_1); - for (j = 0; j < w; j += 8) { - /* Horizontal filter */ - { + __m256i filt[4], coeffs_x[4], coeffs_y[4]; + + filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2); + filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32)); + + prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_x); + prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_y); + + // Condition for checking valid horz_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_x[0], coeffs_x[3]), 0))) + is_horiz_4tap = 1; + + // Condition for checking valid vert_filt taps + if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_y[0], coeffs_y[3]), 0))) + is_vert_4tap = 1; + + if (is_horiz_4tap) { + int im_h = h + filter_params_y->taps - 1; + const int fo_vert = filter_params_y->taps / 2 - 1; + const int fo_horiz = 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; + for (int j = 0; j < w; j += 8) { + /* Horizontal filter */ const uint8_t *src_h = src_ptr + j; for (i = 0; i < im_h; i += 2) { __m256i data = @@ -396,49 +659,59 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride, data = _mm256_inserti128_si256( data, _mm_loadu_si128((__m128i *)(src_h + src_stride)), 1); src_h += (src_stride << 1); - __m256i res = convolve_lowbd_x(data, coeffs_x, filt); + __m256i res = convolve_lowbd_x_4tap(data, coeffs_x + 1, filt); res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); } + DIST_WTD_CONVOLVE_VERTICAL_FILTER_8TAP; } + } else if (is_vert_4tap) { + int im_h = h + 3; + const int fo_vert = 1; + const int fo_horiz = filter_params_x->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; - /* Vertical filter */ - { + filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); + filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); + + for (int j = 0; j < w; j += 8) { + /* Horizontal filter */ + const uint8_t *src_h = src_ptr + j; + DIST_WTD_CONVOLVE_HORIZONTAL_FILTER_8TAP; + + /* Vertical filter */ + __m256i s[6]; __m256i s0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); __m256i s1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); __m256i s2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); __m256i s3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); - __m256i s4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); - __m256i s5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); s[0] = _mm256_unpacklo_epi16(s0, s1); s[1] = _mm256_unpacklo_epi16(s2, s3); - s[2] = _mm256_unpacklo_epi16(s4, s5); - s[4] = _mm256_unpackhi_epi16(s0, s1); - s[5] = _mm256_unpackhi_epi16(s2, s3); - s[6] = _mm256_unpackhi_epi16(s4, s5); + s[3] = _mm256_unpackhi_epi16(s0, s1); + s[4] = _mm256_unpackhi_epi16(s2, s3); for (i = 0; i < h; i += 2) { const int16_t *data = &im_block[i * im_stride]; - const __m256i s6 = - _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); - const __m256i s7 = - _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); + const __m256i s4 = + _mm256_loadu_si256((__m256i *)(data + 4 * im_stride)); + const __m256i s5 = + _mm256_loadu_si256((__m256i *)(data + 5 * im_stride)); - s[3] = _mm256_unpacklo_epi16(s6, s7); - s[7] = _mm256_unpackhi_epi16(s6, s7); + s[2] = _mm256_unpacklo_epi16(s4, s5); + s[5] = _mm256_unpackhi_epi16(s4, s5); - const __m256i res_a = convolve(s, coeffs_y); + const __m256i res_a = convolve_4tap(s, coeffs_y + 1); const __m256i res_a_round = _mm256_sra_epi32( _mm256_add_epi32(res_a, round_const_v), round_shift_v); if (w - j > 4) { - const __m256i res_b = convolve(s + 4, coeffs_y); + const __m256i res_b = convolve_4tap(s + 3, coeffs_y + 1); const __m256i res_b_round = _mm256_sra_epi32( _mm256_add_epi32(res_b, round_const_v), round_shift_v); const __m256i res_16b = _mm256_packs_epi32(res_a_round, res_b_round); @@ -504,16 +777,28 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride, res_1); } } - s[0] = s[1]; s[1] = s[2]; - s[2] = s[3]; - + s[3] = s[4]; s[4] = s[5]; - s[5] = s[6]; - s[6] = s[7]; } } + } else { + int im_h = h + filter_params_y->taps - 1; + const int fo_vert = filter_params_y->taps / 2 - 1; + const int fo_horiz = filter_params_x->taps / 2 - 1; + const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz; + + filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2)); + filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3)); + + for (int j = 0; j < w; j += 8) { + /* Horizontal filter */ + const uint8_t *src_h = src_ptr + j; + DIST_WTD_CONVOLVE_HORIZONTAL_FILTER_8TAP; + + DIST_WTD_CONVOLVE_VERTICAL_FILTER_8TAP; + } } } diff --git a/third_party/aom/av1/common/x86/wiener_convolve_avx2.c b/third_party/aom/av1/common/x86/wiener_convolve_avx2.c index 1f13e2f92e..87a6e12396 100644 --- a/third_party/aom/av1/common/x86/wiener_convolve_avx2.c +++ b/third_party/aom/av1/common/x86/wiener_convolve_avx2.c @@ -17,7 +17,6 @@ #include "av1/common/convolve.h" #include "aom_dsp/aom_dsp_common.h" #include "aom_dsp/aom_filter.h" -#include "aom_dsp/x86/convolve_avx2.h" #include "aom_dsp/x86/synonyms.h" #include "aom_dsp/x86/synonyms_avx2.h" @@ -26,207 +25,236 @@ // on the left. // A row of, say, 8-bit pixels with values p0, p1, p2, ..., p30, p31 will be // loaded and stored as [ p31 ... p17 p16 ][ p15 ... p1 p0 ]. - -// Exploiting the range of wiener filter coefficients, -// horizontal filtering can be done in 16 bit intermediate precision. -// The details are as follows : -// Consider the horizontal wiener filter coefficients of the following form : -// [C0, C1, C2, 2^(FILTER_BITS) -2 * (C0 + C1 + C2), C2, C1, C0] -// Subtracting 2^(FILTER_BITS) from the centre tap we get the following : -// [C0, C1, C2, -2 * (C0 + C1 + C2), C2, C1, C0] -// The sum of the product "C0 * p0 + C1 * p1 + C2 * p2 -2 * (C0 + C1 + C2) * p3 -// + C2 * p4 + C1 * p5 + C0 * p6" would be in the range of signed 16 bit -// precision. Finally, after rounding the above result by round_0, we multiply -// the centre pixel by 2^(FILTER_BITS - round_0) and add it to get the -// horizontal filter output. - void av1_wiener_convolve_add_src_avx2(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4, const int16_t *filter_y, int y_step_q4, int w, int h, const ConvolveParams *conv_params) { + const int bd = 8; assert(x_step_q4 == 16 && y_step_q4 == 16); assert(!(w & 7)); (void)x_step_q4; (void)y_step_q4; - DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + SUBPEL_TAPS) * 8]); - int im_h = h + SUBPEL_TAPS - 2; - int im_stride = 8; - memset(im_block + (im_h * im_stride), 0, MAX_SB_SIZE); - int i, j; - const int center_tap = (SUBPEL_TAPS - 1) / 2; + DECLARE_ALIGNED(32, uint16_t, + temp[(MAX_SB_SIZE + SUBPEL_TAPS - 1) * MAX_SB_SIZE]); + int intermediate_height = h + SUBPEL_TAPS - 2; + memset(temp + (intermediate_height * MAX_SB_SIZE), 0, MAX_SB_SIZE); + const int center_tap = ((SUBPEL_TAPS - 1) / 2); const uint8_t *const src_ptr = src - center_tap * src_stride - center_tap; - __m256i filt[4], coeffs_h[4], coeffs_v[4], filt_center; - - assert(conv_params->round_0 > 0); - - filt[0] = _mm256_load_si256((__m256i const *)filt1_global_avx2); - filt[1] = _mm256_load_si256((__m256i const *)filt2_global_avx2); - filt[2] = _mm256_load_si256((__m256i const *)filt3_global_avx2); - filt[3] = _mm256_load_si256((__m256i const *)filt4_global_avx2); - - filt_center = _mm256_load_si256((__m256i const *)filt_center_global_avx2); - - const __m128i coeffs_x = _mm_loadu_si128((__m128i *)filter_x); - const __m256i filter_coeffs_x = _mm256_broadcastsi128_si256(coeffs_x); - - // coeffs 0 1 0 1 0 1 0 1 - coeffs_h[0] = - _mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0200u)); - // coeffs 2 3 2 3 2 3 2 3 - coeffs_h[1] = - _mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0604u)); - // coeffs 4 5 4 5 4 5 4 5 - coeffs_h[2] = - _mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0a08u)); - // coeffs 6 7 6 7 6 7 6 7 - coeffs_h[3] = - _mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0e0cu)); - - const __m256i round_const_h = - _mm256_set1_epi16((1 << (conv_params->round_0 - 1))); - const __m128i round_shift_h = _mm_cvtsi32_si128(conv_params->round_0); + const __m128i zero_128 = _mm_setzero_si128(); + const __m256i zero_256 = _mm256_setzero_si256(); // Add an offset to account for the "add_src" part of the convolve function. - const __m128i zero_128 = _mm_setzero_si128(); - const __m128i offset_0 = _mm_insert_epi16(zero_128, 1 << FILTER_BITS, 3); - const __m128i coeffs_y = _mm_add_epi16(xx_loadu_128(filter_y), offset_0); + const __m128i offset = _mm_insert_epi16(zero_128, 1 << FILTER_BITS, 3); - const __m256i filter_coeffs_y = _mm256_broadcastsi128_si256(coeffs_y); + const __m256i clamp_low = zero_256; + const __m256i clamp_high = + _mm256_set1_epi16(WIENER_CLAMP_LIMIT(conv_params->round_0, bd) - 1); - // coeffs 0 1 0 1 0 1 0 1 - coeffs_v[0] = _mm256_shuffle_epi32(filter_coeffs_y, 0x00); - // coeffs 2 3 2 3 2 3 2 3 - coeffs_v[1] = _mm256_shuffle_epi32(filter_coeffs_y, 0x55); - // coeffs 4 5 4 5 4 5 4 5 - coeffs_v[2] = _mm256_shuffle_epi32(filter_coeffs_y, 0xaa); - // coeffs 6 7 6 7 6 7 6 7 - coeffs_v[3] = _mm256_shuffle_epi32(filter_coeffs_y, 0xff); + /* Horizontal filter */ + { + // coeffs [ f7 f6 f5 f4 f3 f2 f1 f0 ] + const __m128i coeffs_x = _mm_add_epi16(xx_loadu_128(filter_x), offset); - const __m256i round_const_v = - _mm256_set1_epi32((1 << (conv_params->round_1 - 1))); - const __m128i round_shift_v = _mm_cvtsi32_si128(conv_params->round_1); + // coeffs [ f3 f2 f3 f2 f1 f0 f1 f0 ] + const __m128i coeffs_0123 = _mm_unpacklo_epi32(coeffs_x, coeffs_x); + // coeffs [ f7 f6 f7 f6 f5 f4 f5 f4 ] + const __m128i coeffs_4567 = _mm_unpackhi_epi32(coeffs_x, coeffs_x); - for (j = 0; j < w; j += 8) { - for (i = 0; i < im_h; i += 2) { - __m256i data = _mm256_castsi128_si256( - _mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); + // coeffs [ f1 f0 f1 f0 f1 f0 f1 f0 ] + const __m128i coeffs_01_128 = _mm_unpacklo_epi64(coeffs_0123, coeffs_0123); + // coeffs [ f3 f2 f3 f2 f3 f2 f3 f2 ] + const __m128i coeffs_23_128 = _mm_unpackhi_epi64(coeffs_0123, coeffs_0123); + // coeffs [ f5 f4 f5 f4 f5 f4 f5 f4 ] + const __m128i coeffs_45_128 = _mm_unpacklo_epi64(coeffs_4567, coeffs_4567); + // coeffs [ f7 f6 f7 f6 f7 f6 f7 f6 ] + const __m128i coeffs_67_128 = _mm_unpackhi_epi64(coeffs_4567, coeffs_4567); - // Load the next line - if (i + 1 < im_h) - data = _mm256_inserti128_si256( - data, - _mm_loadu_si128( - (__m128i *)&src_ptr[(i * src_stride) + j + src_stride]), - 1); + // coeffs [ f1 f0 f1 f0 f1 f0 f1 f0 ][ f1 f0 f1 f0 f1 f0 f1 f0 ] + const __m256i coeffs_01 = yy_set_m128i(coeffs_01_128, coeffs_01_128); + // coeffs [ f3 f2 f3 f2 f3 f2 f3 f2 ][ f3 f2 f3 f2 f3 f2 f3 f2 ] + const __m256i coeffs_23 = yy_set_m128i(coeffs_23_128, coeffs_23_128); + // coeffs [ f5 f4 f5 f4 f5 f4 f5 f4 ][ f5 f4 f5 f4 f5 f4 f5 f4 ] + const __m256i coeffs_45 = yy_set_m128i(coeffs_45_128, coeffs_45_128); + // coeffs [ f7 f6 f7 f6 f7 f6 f7 f6 ][ f7 f6 f7 f6 f7 f6 f7 f6 ] + const __m256i coeffs_67 = yy_set_m128i(coeffs_67_128, coeffs_67_128); - __m256i res = convolve_lowbd_x(data, coeffs_h, filt); + const __m256i round_const = _mm256_set1_epi32( + (1 << (conv_params->round_0 - 1)) + (1 << (bd + FILTER_BITS - 1))); - res = - _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); + for (int i = 0; i < intermediate_height; ++i) { + for (int j = 0; j < w; j += 16) { + const uint8_t *data_ij = src_ptr + i * src_stride + j; - __m256i data_0 = _mm256_shuffle_epi8(data, filt_center); + // Load 8-bit src data + const __m128i data_0 = xx_loadu_128(data_ij + 0); + const __m128i data_1 = xx_loadu_128(data_ij + 1); + const __m128i data_2 = xx_loadu_128(data_ij + 2); + const __m128i data_3 = xx_loadu_128(data_ij + 3); + const __m128i data_4 = xx_loadu_128(data_ij + 4); + const __m128i data_5 = xx_loadu_128(data_ij + 5); + const __m128i data_6 = xx_loadu_128(data_ij + 6); + const __m128i data_7 = xx_loadu_128(data_ij + 7); - // multiply the center pixel by 2^(FILTER_BITS - round_0) and add it to - // the result - data_0 = _mm256_slli_epi16(data_0, FILTER_BITS - conv_params->round_0); - res = _mm256_add_epi16(res, data_0); + // (Zero-)Extend 8-bit data to 16-bit data + const __m256i src_0 = _mm256_cvtepu8_epi16(data_0); + const __m256i src_1 = _mm256_cvtepu8_epi16(data_1); + const __m256i src_2 = _mm256_cvtepu8_epi16(data_2); + const __m256i src_3 = _mm256_cvtepu8_epi16(data_3); + const __m256i src_4 = _mm256_cvtepu8_epi16(data_4); + const __m256i src_5 = _mm256_cvtepu8_epi16(data_5); + const __m256i src_6 = _mm256_cvtepu8_epi16(data_6); + const __m256i src_7 = _mm256_cvtepu8_epi16(data_7); - _mm256_store_si256((__m256i *)&im_block[i * im_stride], res); - } + // Multiply src data by filter coeffs and sum pairs + const __m256i res_0 = _mm256_madd_epi16(src_0, coeffs_01); + const __m256i res_1 = _mm256_madd_epi16(src_1, coeffs_01); + const __m256i res_2 = _mm256_madd_epi16(src_2, coeffs_23); + const __m256i res_3 = _mm256_madd_epi16(src_3, coeffs_23); + const __m256i res_4 = _mm256_madd_epi16(src_4, coeffs_45); + const __m256i res_5 = _mm256_madd_epi16(src_5, coeffs_45); + const __m256i res_6 = _mm256_madd_epi16(src_6, coeffs_67); + const __m256i res_7 = _mm256_madd_epi16(src_7, coeffs_67); - /* Vertical filter */ - { - __m256i src_0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); - __m256i src_1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); - __m256i src_2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); - __m256i src_3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); - __m256i src_4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); - __m256i src_5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); + // Calculate scalar product for even- and odd-indices separately, + // increasing to 32-bit precision + const __m256i res_even_sum = _mm256_add_epi32( + _mm256_add_epi32(res_0, res_4), _mm256_add_epi32(res_2, res_6)); + const __m256i res_odd_sum = _mm256_add_epi32( + _mm256_add_epi32(res_1, res_5), _mm256_add_epi32(res_3, res_7)); - __m256i s[8]; - s[0] = _mm256_unpacklo_epi16(src_0, src_1); - s[1] = _mm256_unpacklo_epi16(src_2, src_3); - s[2] = _mm256_unpacklo_epi16(src_4, src_5); + const __m256i res_even = _mm256_srai_epi32( + _mm256_add_epi32(res_even_sum, round_const), conv_params->round_0); + const __m256i res_odd = _mm256_srai_epi32( + _mm256_add_epi32(res_odd_sum, round_const), conv_params->round_0); - s[4] = _mm256_unpackhi_epi16(src_0, src_1); - s[5] = _mm256_unpackhi_epi16(src_2, src_3); - s[6] = _mm256_unpackhi_epi16(src_4, src_5); + // Reduce to 16-bit precision and pack even- and odd-index results + // back into one register. The _mm256_packs_epi32 intrinsic returns + // a register with the pixels ordered as follows: + // [ 15 13 11 9 14 12 10 8 ] [ 7 5 3 1 6 4 2 0 ] + const __m256i res = _mm256_packs_epi32(res_even, res_odd); + const __m256i res_clamped = + _mm256_min_epi16(_mm256_max_epi16(res, clamp_low), clamp_high); - for (i = 0; i < h - 1; i += 2) { - const int16_t *data = &im_block[i * im_stride]; - - const __m256i s6 = - _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); - const __m256i s7 = - _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); - - s[3] = _mm256_unpacklo_epi16(s6, s7); - s[7] = _mm256_unpackhi_epi16(s6, s7); - - __m256i res_a = convolve(s, coeffs_v); - __m256i res_b = convolve(s + 4, coeffs_v); - - const __m256i res_a_round = _mm256_sra_epi32( - _mm256_add_epi32(res_a, round_const_v), round_shift_v); - const __m256i res_b_round = _mm256_sra_epi32( - _mm256_add_epi32(res_b, round_const_v), round_shift_v); - - /* rounding code */ - // 16 bit conversion - const __m256i res_16bit = _mm256_packs_epi32(res_a_round, res_b_round); - // 8 bit conversion and saturation to uint8 - const __m256i res_8b = _mm256_packus_epi16(res_16bit, res_16bit); - - const __m128i res_0 = _mm256_castsi256_si128(res_8b); - const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1); - - // Store values into the destination buffer - __m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; - __m128i *const p_1 = (__m128i *)&dst[i * dst_stride + j + dst_stride]; - - _mm_storel_epi64(p_0, res_0); - _mm_storel_epi64(p_1, res_1); - - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - - s[4] = s[5]; - s[5] = s[6]; - s[6] = s[7]; + // Store in a temporary array + yy_storeu_256(temp + i * MAX_SB_SIZE + j, res_clamped); } - if (h - i) { - s[0] = _mm256_permute2x128_si256(s[0], s[4], 0x20); - s[1] = _mm256_permute2x128_si256(s[1], s[5], 0x20); - s[2] = _mm256_permute2x128_si256(s[2], s[6], 0x20); + } + } - const int16_t *data = &im_block[i * im_stride]; - const __m128i s6_ = _mm_loadu_si128((__m128i *)(data + 6 * im_stride)); - const __m128i s7_ = _mm_loadu_si128((__m128i *)(data + 7 * im_stride)); + /* Vertical filter */ + { + // coeffs [ g7 g6 g5 g4 g3 g2 g1 g0 ] + const __m128i coeffs_y = _mm_add_epi16(xx_loadu_128(filter_y), offset); - __m128i s3 = _mm_unpacklo_epi16(s6_, s7_); - __m128i s7 = _mm_unpackhi_epi16(s6_, s7_); + // coeffs [ g3 g2 g3 g2 g1 g0 g1 g0 ] + const __m128i coeffs_0123 = _mm_unpacklo_epi32(coeffs_y, coeffs_y); + // coeffs [ g7 g6 g7 g6 g5 g4 g5 g4 ] + const __m128i coeffs_4567 = _mm_unpackhi_epi32(coeffs_y, coeffs_y); - s[3] = _mm256_inserti128_si256(_mm256_castsi128_si256(s3), s7, 1); - __m256i convolveres = convolve(s, coeffs_v); + // coeffs [ g1 g0 g1 g0 g1 g0 g1 g0 ] + const __m128i coeffs_01_128 = _mm_unpacklo_epi64(coeffs_0123, coeffs_0123); + // coeffs [ g3 g2 g3 g2 g3 g2 g3 g2 ] + const __m128i coeffs_23_128 = _mm_unpackhi_epi64(coeffs_0123, coeffs_0123); + // coeffs [ g5 g4 g5 g4 g5 g4 g5 g4 ] + const __m128i coeffs_45_128 = _mm_unpacklo_epi64(coeffs_4567, coeffs_4567); + // coeffs [ g7 g6 g7 g6 g7 g6 g7 g6 ] + const __m128i coeffs_67_128 = _mm_unpackhi_epi64(coeffs_4567, coeffs_4567); - const __m256i res_round = _mm256_sra_epi32( - _mm256_add_epi32(convolveres, round_const_v), round_shift_v); + // coeffs [ g1 g0 g1 g0 g1 g0 g1 g0 ][ g1 g0 g1 g0 g1 g0 g1 g0 ] + const __m256i coeffs_01 = yy_set_m128i(coeffs_01_128, coeffs_01_128); + // coeffs [ g3 g2 g3 g2 g3 g2 g3 g2 ][ g3 g2 g3 g2 g3 g2 g3 g2 ] + const __m256i coeffs_23 = yy_set_m128i(coeffs_23_128, coeffs_23_128); + // coeffs [ g5 g4 g5 g4 g5 g4 g5 g4 ][ g5 g4 g5 g4 g5 g4 g5 g4 ] + const __m256i coeffs_45 = yy_set_m128i(coeffs_45_128, coeffs_45_128); + // coeffs [ g7 g6 g7 g6 g7 g6 g7 g6 ][ g7 g6 g7 g6 g7 g6 g7 g6 ] + const __m256i coeffs_67 = yy_set_m128i(coeffs_67_128, coeffs_67_128); - /* rounding code */ - // 16 bit conversion - __m128i reslo = _mm256_castsi256_si128(res_round); - __m128i reshi = _mm256_extracti128_si256(res_round, 1); - const __m128i res_16bit = _mm_packus_epi32(reslo, reshi); + const __m256i round_const = + _mm256_set1_epi32((1 << (conv_params->round_1 - 1)) - + (1 << (bd + conv_params->round_1 - 1))); - // 8 bit conversion and saturation to uint8 - const __m128i res_8b = _mm_packus_epi16(res_16bit, res_16bit); - __m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; - _mm_storel_epi64(p_0, res_8b); + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; j += 16) { + const uint16_t *data_ij = temp + i * MAX_SB_SIZE + j; + + // Load 16-bit data from the output of the horizontal filter in + // which the pixels are ordered as follows: + // [ 15 13 11 9 14 12 10 8 ] [ 7 5 3 1 6 4 2 0 ] + const __m256i data_0 = yy_loadu_256(data_ij + 0 * MAX_SB_SIZE); + const __m256i data_1 = yy_loadu_256(data_ij + 1 * MAX_SB_SIZE); + const __m256i data_2 = yy_loadu_256(data_ij + 2 * MAX_SB_SIZE); + const __m256i data_3 = yy_loadu_256(data_ij + 3 * MAX_SB_SIZE); + const __m256i data_4 = yy_loadu_256(data_ij + 4 * MAX_SB_SIZE); + const __m256i data_5 = yy_loadu_256(data_ij + 5 * MAX_SB_SIZE); + const __m256i data_6 = yy_loadu_256(data_ij + 6 * MAX_SB_SIZE); + const __m256i data_7 = yy_loadu_256(data_ij + 7 * MAX_SB_SIZE); + + // Filter the even-indices, increasing to 32-bit precision + const __m256i src_0 = _mm256_unpacklo_epi16(data_0, data_1); + const __m256i src_2 = _mm256_unpacklo_epi16(data_2, data_3); + const __m256i src_4 = _mm256_unpacklo_epi16(data_4, data_5); + const __m256i src_6 = _mm256_unpacklo_epi16(data_6, data_7); + + const __m256i res_0 = _mm256_madd_epi16(src_0, coeffs_01); + const __m256i res_2 = _mm256_madd_epi16(src_2, coeffs_23); + const __m256i res_4 = _mm256_madd_epi16(src_4, coeffs_45); + const __m256i res_6 = _mm256_madd_epi16(src_6, coeffs_67); + + const __m256i res_even = _mm256_add_epi32( + _mm256_add_epi32(res_0, res_2), _mm256_add_epi32(res_4, res_6)); + + // Filter the odd-indices, increasing to 32-bit precision + const __m256i src_1 = _mm256_unpackhi_epi16(data_0, data_1); + const __m256i src_3 = _mm256_unpackhi_epi16(data_2, data_3); + const __m256i src_5 = _mm256_unpackhi_epi16(data_4, data_5); + const __m256i src_7 = _mm256_unpackhi_epi16(data_6, data_7); + + const __m256i res_1 = _mm256_madd_epi16(src_1, coeffs_01); + const __m256i res_3 = _mm256_madd_epi16(src_3, coeffs_23); + const __m256i res_5 = _mm256_madd_epi16(src_5, coeffs_45); + const __m256i res_7 = _mm256_madd_epi16(src_7, coeffs_67); + + const __m256i res_odd = _mm256_add_epi32( + _mm256_add_epi32(res_1, res_3), _mm256_add_epi32(res_5, res_7)); + + // Pixels are currently in the following order: + // res_even order: [ 14 12 10 8 ] [ 6 4 2 0 ] + // res_odd order: [ 15 13 11 9 ] [ 7 5 3 1 ] + // + // Rearrange the pixels into the following order: + // res_lo order: [ 11 10 9 8 ] [ 3 2 1 0 ] + // res_hi order: [ 15 14 13 12 ] [ 7 6 5 4 ] + const __m256i res_lo = _mm256_unpacklo_epi32(res_even, res_odd); + const __m256i res_hi = _mm256_unpackhi_epi32(res_even, res_odd); + + const __m256i res_lo_round = _mm256_srai_epi32( + _mm256_add_epi32(res_lo, round_const), conv_params->round_1); + const __m256i res_hi_round = _mm256_srai_epi32( + _mm256_add_epi32(res_hi, round_const), conv_params->round_1); + + // Reduce to 16-bit precision and pack into the correct order: + // [ 15 14 13 12 11 10 9 8 ][ 7 6 5 4 3 2 1 0 ] + const __m256i res_16bit = + _mm256_packs_epi32(res_lo_round, res_hi_round); + + // Reduce to 8-bit precision. This messes up the order: + // [ - - - - - - - - 15 14 13 12 11 10 9 8 ] + // [ - - - - - - - - 7 6 5 4 3 2 1 0 ] + const __m256i res_8bit = + _mm256_packus_epi16(res_16bit, zero_256 /* don't care value */); + + // Swap the two central 32-bit values to get the order: + // [ - - - - - - - - - - - - - - - - ] + // [ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] + const __m256i res_8bit2 = _mm256_permute4x64_epi64(res_8bit, 0xd8); + + // Store the lower 128-bit lane in the dst array + xx_storeu_128(dst + i * dst_stride + j, + _mm256_castsi256_si128(res_8bit2)); } } } diff --git a/third_party/aom/av1/decoder/decodeframe.c b/third_party/aom/av1/decoder/decodeframe.c index 26e91d5ac8..b7fc3709e0 100644 --- a/third_party/aom/av1/decoder/decodeframe.c +++ b/third_party/aom/av1/decoder/decodeframe.c @@ -781,7 +781,7 @@ static INLINE void dec_build_inter_predictors(const AV1_COMMON *cm, dec_calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, 0, 0, pre_buf, &subpel_params[ref], bw, bh, &block, mi_x, mi_y, &scaled_mv, &subpel_x_mv, &subpel_y_mv); - pre[ref] = pre_buf->buf0 + block.y0 * pre_buf->stride + block.x0; + pre[ref] = pre_buf->buf0 + (int64_t)block.y0 * pre_buf->stride + block.x0; src_stride[ref] = pre_buf->stride; highbd = is_cur_buf_hbd(xd); @@ -4240,6 +4240,25 @@ void av1_read_film_grain_params(AV1_COMMON *cm, if (!pars->update_parameters) { // inherit parameters from a previous reference frame int film_grain_params_ref_idx = aom_rb_read_literal(rb, 3); + // Section 6.8.20: It is a requirement of bitstream conformance that + // film_grain_params_ref_idx is equal to ref_frame_idx[ j ] for some value + // of j in the range 0 to REFS_PER_FRAME - 1. + int found = 0; + for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { + if (film_grain_params_ref_idx == cm->remapped_ref_idx[i]) { + found = 1; + break; + } + } + if (!found) { + aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, + "Invalid film grain reference idx %d. ref_frame_idx = " + "{%d, %d, %d, %d, %d, %d, %d}", + film_grain_params_ref_idx, cm->remapped_ref_idx[0], + cm->remapped_ref_idx[1], cm->remapped_ref_idx[2], + cm->remapped_ref_idx[3], cm->remapped_ref_idx[4], + cm->remapped_ref_idx[5], cm->remapped_ref_idx[6]); + } RefCntBuffer *const buf = cm->ref_frame_map[film_grain_params_ref_idx]; if (buf == NULL) { aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, @@ -4468,13 +4487,13 @@ void av1_read_timing_info_header(AV1_COMMON *cm, cm->timing_info.equal_picture_interval = aom_rb_read_bit(rb); // Equal picture interval bit if (cm->timing_info.equal_picture_interval) { - cm->timing_info.num_ticks_per_picture = - aom_rb_read_uvlc(rb) + 1; // ticks per picture - if (cm->timing_info.num_ticks_per_picture == 0) { + const uint32_t num_ticks_per_picture_minus_1 = aom_rb_read_uvlc(rb); + if (num_ticks_per_picture_minus_1 == UINT32_MAX) { aom_internal_error( &cm->error, AOM_CODEC_UNSUP_BITSTREAM, "num_ticks_per_picture_minus_1 cannot be (1 << 32) − 1."); } + cm->timing_info.num_ticks_per_picture = num_ticks_per_picture_minus_1 + 1; } } @@ -5179,7 +5198,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Inter frame requests nonexistent reference"); - av1_set_frame_refs(cm, lst_ref, gld_ref); + av1_set_frame_refs(cm, cm->remapped_ref_idx, lst_ref, gld_ref); } for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { @@ -5189,7 +5208,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, // Most of the time, streams start with a keyframe. In that case, // ref_frame_map will have been filled in at that point and will not - // contain any -1's. However, streams are explicitly allowed to start + // contain any NULLs. However, streams are explicitly allowed to start // with an intra-only frame, so long as they don't then signal a // reference to a slot that hasn't been set yet. That's what we are // checking here. @@ -5319,6 +5338,11 @@ static int read_uncompressed_header(AV1Decoder *pbi, } read_tile_info(pbi, rb); + if (!is_min_tile_width_satisfied(cm)) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "Minimum tile width requirement not satisfied"); + } + setup_quantization(cm, rb); xd->bd = (int)seq_params->bit_depth; diff --git a/third_party/aom/av1/decoder/decodemv.c b/third_party/aom/av1/decoder/decodemv.c index b7431f2489..2791f3a0da 100644 --- a/third_party/aom/av1/decoder/decodemv.c +++ b/third_party/aom/av1/decoder/decodemv.c @@ -678,11 +678,10 @@ static void read_intrabc_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, int16_t inter_mode_ctx[MODE_CTX_REF_FRAMES]; int_mv ref_mvs[INTRA_FRAME + 1][MAX_MV_REF_CANDIDATES]; - int_mv global_mvs[REF_FRAMES]; av1_find_mv_refs(cm, xd, mbmi, INTRA_FRAME, xd->ref_mv_count, - xd->ref_mv_stack, ref_mvs, global_mvs, mi_row, mi_col, - inter_mode_ctx); + xd->ref_mv_stack, ref_mvs, /*global_mvs=*/NULL, mi_row, + mi_col, inter_mode_ctx); int_mv nearestmv, nearmv; @@ -1271,9 +1270,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, const int is_compound = has_second_ref(mbmi); MV_REFERENCE_FRAME ref_frame = av1_ref_frame_type(mbmi->ref_frame); - int_mv global_mvs[REF_FRAMES]; av1_find_mv_refs(cm, xd, mbmi, ref_frame, xd->ref_mv_count, xd->ref_mv_stack, - ref_mvs, global_mvs, mi_row, mi_col, inter_mode_ctx); + ref_mvs, /*global_mvs=*/NULL, mi_row, mi_col, + inter_mode_ctx); int mode_ctx = av1_mode_context_analyzer(inter_mode_ctx, mbmi->ref_frame); mbmi->ref_mv_idx = 0; @@ -1421,9 +1420,12 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, const int comp_index_ctx = get_comp_index_context(cm, xd); mbmi->compound_idx = aom_read_symbol( r, ec_ctx->compound_index_cdf[comp_index_ctx], 2, ACCT_STR); + mbmi->interinter_comp.type = + mbmi->compound_idx ? COMPOUND_AVERAGE : COMPOUND_DISTWTD; } else { // Distance-weighted compound is disabled, so always use average mbmi->compound_idx = 1; + mbmi->interinter_comp.type = COMPOUND_AVERAGE; } } else { assert(cm->current_frame.reference_mode != SINGLE_REFERENCE && @@ -1434,8 +1436,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, // compound_diffwtd, wedge if (is_interinter_compound_used(COMPOUND_WEDGE, bsize)) mbmi->interinter_comp.type = - 1 + aom_read_symbol(r, ec_ctx->compound_type_cdf[bsize], - COMPOUND_TYPES - 1, ACCT_STR); + COMPOUND_WEDGE + aom_read_symbol(r, + ec_ctx->compound_type_cdf[bsize], + MASKED_COMPOUND_TYPES, ACCT_STR); else mbmi->interinter_comp.type = COMPOUND_DIFFWTD; diff --git a/third_party/aom/av1/decoder/decoder.h b/third_party/aom/av1/decoder/decoder.h index 467c8a2fc1..685c931119 100644 --- a/third_party/aom/av1/decoder/decoder.h +++ b/third_party/aom/av1/decoder/decoder.h @@ -48,9 +48,9 @@ typedef void (*cfl_store_inter_block_visitor_fn_t)(AV1_COMMON *const cm, MACROBLOCKD *const xd); typedef struct ThreadData { - aom_reader *bit_reader; DECLARE_ALIGNED(32, MACROBLOCKD, xd); CB_BUFFER cb_buffer_base; + aom_reader *bit_reader; uint8_t *mc_buf[2]; int32_t mc_buf_size; int mc_buf_use_highbd; // Boolean: whether the byte pointers stored in diff --git a/third_party/aom/av1/decoder/dthread.c b/third_party/aom/av1/decoder/dthread.c deleted file mode 100644 index 3946c787a1..0000000000 --- a/third_party/aom/av1/decoder/dthread.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2016, 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 "config/aom_config.h" - -#include "aom_mem/aom_mem.h" -#include "av1/common/reconinter.h" -#include "av1/decoder/dthread.h" -#include "av1/decoder/decoder.h" - -// #define DEBUG_THREAD - -// TODO(hkuang): Clean up all the #ifdef in this file. -void av1_frameworker_lock_stats(AVxWorker *const worker) { -#if CONFIG_MULTITHREAD - FrameWorkerData *const worker_data = worker->data1; - pthread_mutex_lock(&worker_data->stats_mutex); -#else - (void)worker; -#endif -} - -void av1_frameworker_unlock_stats(AVxWorker *const worker) { -#if CONFIG_MULTITHREAD - FrameWorkerData *const worker_data = worker->data1; - pthread_mutex_unlock(&worker_data->stats_mutex); -#else - (void)worker; -#endif -} - -void av1_frameworker_signal_stats(AVxWorker *const worker) { -#if CONFIG_MULTITHREAD - FrameWorkerData *const worker_data = worker->data1; - -// TODO(hkuang): Fix the pthread_cond_broadcast in windows wrapper. -#if defined(_WIN32) && !HAVE_PTHREAD_H - pthread_cond_signal(&worker_data->stats_cond); -#else - pthread_cond_broadcast(&worker_data->stats_cond); -#endif - -#else - (void)worker; -#endif -} - -// This macro prevents thread_sanitizer from reporting known concurrent writes. -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#define BUILDING_WITH_TSAN -#endif -#endif - -// TODO(hkuang): Remove worker parameter as it is only used in debug code. -void av1_frameworker_wait(AVxWorker *const worker, RefCntBuffer *const ref_buf, - int row) { -#if CONFIG_MULTITHREAD - if (!ref_buf) return; - -#ifndef BUILDING_WITH_TSAN - // The following line of code will get harmless tsan error but it is the key - // to get best performance. - if (ref_buf->row >= row && ref_buf->buf.corrupted != 1) return; -#endif - - { - // Find the worker thread that owns the reference frame. If the reference - // frame has been fully decoded, it may not have owner. - AVxWorker *const ref_worker = ref_buf->frame_worker_owner; - FrameWorkerData *const ref_worker_data = - (FrameWorkerData *)ref_worker->data1; - const AV1Decoder *const pbi = ref_worker_data->pbi; - -#ifdef DEBUG_THREAD - { - FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1; - printf("%d %p worker is waiting for %d %p worker (%d) ref %d \r\n", - worker_data->worker_id, worker, ref_worker_data->worker_id, - ref_buf->frame_worker_owner, row, ref_buf->row); - } -#endif - - av1_frameworker_lock_stats(ref_worker); - while (ref_buf->row < row && pbi->cur_buf == ref_buf && - ref_buf->buf.corrupted != 1) { - pthread_cond_wait(&ref_worker_data->stats_cond, - &ref_worker_data->stats_mutex); - } - - if (ref_buf->buf.corrupted == 1) { - FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1; - av1_frameworker_unlock_stats(ref_worker); - aom_internal_error(&worker_data->pbi->common.error, - AOM_CODEC_CORRUPT_FRAME, - "Worker %p failed to decode frame", worker); - } - av1_frameworker_unlock_stats(ref_worker); - } -#else - (void)worker; - (void)ref_buf; - (void)row; - (void)ref_buf; -#endif // CONFIG_MULTITHREAD -} - -void av1_frameworker_broadcast(RefCntBuffer *const buf, int row) { -#if CONFIG_MULTITHREAD - AVxWorker *worker = buf->frame_worker_owner; - -#ifdef DEBUG_THREAD - { - FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1; - printf("%d %p worker decode to (%d) \r\n", worker_data->worker_id, - buf->frame_worker_owner, row); - } -#endif - - av1_frameworker_lock_stats(worker); - buf->row = row; - av1_frameworker_signal_stats(worker); - av1_frameworker_unlock_stats(worker); -#else - (void)buf; - (void)row; -#endif // CONFIG_MULTITHREAD -} - -void av1_frameworker_copy_context(AVxWorker *const dst_worker, - AVxWorker *const src_worker) { -#if CONFIG_MULTITHREAD - FrameWorkerData *const src_worker_data = (FrameWorkerData *)src_worker->data1; - FrameWorkerData *const dst_worker_data = (FrameWorkerData *)dst_worker->data1; - AV1_COMMON *const src_cm = &src_worker_data->pbi->common; - AV1_COMMON *const dst_cm = &dst_worker_data->pbi->common; - int i; - - // Wait until source frame's context is ready. - av1_frameworker_lock_stats(src_worker); - while (!src_worker_data->frame_context_ready) { - pthread_cond_wait(&src_worker_data->stats_cond, - &src_worker_data->stats_mutex); - } - - dst_cm->last_frame_seg_map = src_cm->seg.enabled - ? src_cm->current_frame_seg_map - : src_cm->last_frame_seg_map; - dst_worker_data->pbi->need_resync = src_worker_data->pbi->need_resync; - av1_frameworker_unlock_stats(src_worker); - - dst_cm->seq_params.bit_depth = src_cm->seq_params.bit_depth; - dst_cm->seq_params.use_highbitdepth = src_cm->seq_params.use_highbitdepth; - // TODO(zoeliu): To handle parallel decoding - dst_cm->prev_frame = - src_cm->show_existing_frame ? src_cm->prev_frame : src_cm->cur_frame; - dst_cm->last_width = - !src_cm->show_existing_frame ? src_cm->width : src_cm->last_width; - dst_cm->last_height = - !src_cm->show_existing_frame ? src_cm->height : src_cm->last_height; - dst_cm->seq_params.subsampling_x = src_cm->seq_params.subsampling_x; - dst_cm->seq_params.subsampling_y = src_cm->seq_params.subsampling_y; - dst_cm->frame_type = src_cm->frame_type; - dst_cm->last_show_frame = !src_cm->show_existing_frame - ? src_cm->show_frame - : src_cm->last_show_frame; - for (i = 0; i < REF_FRAMES; ++i) - dst_cm->ref_frame_map[i] = src_cm->next_ref_frame_map[i]; - - memcpy(dst_cm->lf_info.lfthr, src_cm->lf_info.lfthr, - (MAX_LOOP_FILTER + 1) * sizeof(loop_filter_thresh)); - dst_cm->lf.sharpness_level = src_cm->lf.sharpness_level; - dst_cm->lf.filter_level[0] = src_cm->lf.filter_level[0]; - dst_cm->lf.filter_level[1] = src_cm->lf.filter_level[1]; - memcpy(dst_cm->lf.ref_deltas, src_cm->lf.ref_deltas, REF_FRAMES); - memcpy(dst_cm->lf.mode_deltas, src_cm->lf.mode_deltas, MAX_MODE_LF_DELTAS); - dst_cm->seg = src_cm->seg; - memcpy(dst_cm->frame_contexts, src_cm->frame_contexts, - FRAME_CONTEXTS * sizeof(dst_cm->frame_contexts[0])); -#else - (void)dst_worker; - (void)src_worker; -#endif // CONFIG_MULTITHREAD -} diff --git a/third_party/aom/av1/decoder/inspection.c b/third_party/aom/av1/decoder/inspection.c index a027b64e63..eeed1d3222 100644 --- a/third_party/aom/av1/decoder/inspection.c +++ b/third_party/aom/av1/decoder/inspection.c @@ -82,6 +82,9 @@ int ifd_inspect(insp_frame_data *fd, void *decoder, int skip_not_transform) { mi->ref_frame[1] = mbmi->ref_frame[1]; // Prediction Mode mi->mode = mbmi->mode; + mi->intrabc = (int16_t)mbmi->use_intrabc; + mi->palette = (int16_t)mbmi->palette_mode_info.palette_size[0]; + mi->uv_palette = (int16_t)mbmi->palette_mode_info.palette_size[1]; // Prediction Mode for Chromatic planes if (mi->mode < INTRA_MODES) { mi->uv_mode = mbmi->uv_mode; diff --git a/third_party/aom/av1/decoder/inspection.h b/third_party/aom/av1/decoder/inspection.h index ddea4a1543..b963f6ac61 100644 --- a/third_party/aom/av1/decoder/inspection.h +++ b/third_party/aom/av1/decoder/inspection.h @@ -52,6 +52,9 @@ struct insp_mi_data { int16_t current_qindex; int16_t compound_type; int16_t motion_mode; + int16_t intrabc; + int16_t palette; + int16_t uv_palette; }; typedef struct insp_frame_data insp_frame_data; diff --git a/third_party/aom/av1/decoder/obu.c b/third_party/aom/av1/decoder/obu.c index 58f7d2ca8e..aaea572708 100644 --- a/third_party/aom/av1/decoder/obu.c +++ b/third_party/aom/av1/decoder/obu.c @@ -98,12 +98,10 @@ static int byte_alignment(AV1_COMMON *const cm, static uint32_t read_temporal_delimiter_obu() { return 0; } // Returns a boolean that indicates success. -static int read_bitstream_level(BitstreamLevel *bl, +static int read_bitstream_level(AV1_LEVEL *seq_level_idx, struct aom_read_bit_buffer *rb) { - const uint8_t seq_level_idx = aom_rb_read_literal(rb, LEVEL_BITS); - if (!is_valid_seq_level_idx(seq_level_idx)) return 0; - bl->major = (seq_level_idx >> LEVEL_MINOR_BITS) + LEVEL_MAJOR_MIN; - bl->minor = seq_level_idx & ((1 << LEVEL_MINOR_BITS) - 1); + *seq_level_idx = aom_rb_read_literal(rb, LEVEL_BITS); + if (!is_valid_seq_level_idx(*seq_level_idx)) return 0; return 1; } @@ -151,7 +149,7 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi, seq_params->display_model_info_present_flag = 0; seq_params->operating_points_cnt_minus_1 = 0; seq_params->operating_point_idc[0] = 0; - if (!read_bitstream_level(&seq_params->level[0], rb)) { + if (!read_bitstream_level(&seq_params->seq_level_idx[0], rb)) { cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM; return 0; } @@ -175,13 +173,13 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi, for (int i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; i++) { seq_params->operating_point_idc[i] = aom_rb_read_literal(rb, OP_POINTS_IDC_BITS); - if (!read_bitstream_level(&seq_params->level[i], rb)) { + if (!read_bitstream_level(&seq_params->seq_level_idx[i], rb)) { cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM; return 0; } // This is the seq_level_idx[i] > 7 check in the spec. seq_level_idx 7 // is equivalent to level 3.3. - if (seq_params->level[i].major > 3) + if (seq_params->seq_level_idx[i] >= SEQ_LEVEL_4_0) seq_params->tier[i] = aom_rb_read_bit(rb); else seq_params->tier[i] = 0; @@ -195,10 +193,9 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi, if (cm->timing_info_present && (cm->timing_info.equal_picture_interval || cm->op_params[i].decoder_model_param_present_flag)) { - cm->op_params[i].bitrate = max_level_bitrate( - seq_params->profile, - major_minor_to_seq_level_idx(seq_params->level[i]), - seq_params->tier[i]); + cm->op_params[i].bitrate = + max_level_bitrate(seq_params->profile, seq_params->seq_level_idx[i], + seq_params->tier[i]); // Level with seq_level_idx = 31 returns a high "dummy" bitrate to pass // the check if (cm->op_params[i].bitrate == 0) diff --git a/third_party/aom/av1/encoder/aq_cyclicrefresh.c b/third_party/aom/av1/encoder/aq_cyclicrefresh.c index 8d96b23920..bfb2a9017e 100644 --- a/third_party/aom/av1/encoder/aq_cyclicrefresh.c +++ b/third_party/aom/av1/encoder/aq_cyclicrefresh.c @@ -31,9 +31,9 @@ struct CYCLIC_REFRESH { // excess of the cycle time, i.e., in the case of all zero motion, block // will be refreshed every (100/percent_refresh + time_for_refresh) frames. int time_for_refresh; - // Target number of (8x8) blocks that are set for delta-q. + // Target number of (4x4) blocks that are set for delta-q. int target_num_seg_blocks; - // Actual number of (8x8) blocks that were applied delta-q. + // Actual number of (4x4) blocks that were applied delta-q. int actual_num_seg1_blocks; int actual_num_seg2_blocks; // RD mult. parameters for segment 1. @@ -55,6 +55,8 @@ struct CYCLIC_REFRESH { int rate_boost_fac; double low_content_avg; int qindex_delta[3]; + double weight_segment; + int apply_cyclic_refresh; }; CYCLIC_REFRESH *av1_cyclic_refresh_alloc(int mi_rows, int mi_cols) { @@ -87,27 +89,6 @@ void av1_cyclic_refresh_free(CYCLIC_REFRESH *cr) { } } -// Check if we should turn off cyclic refresh based on bitrate condition. -static int apply_cyclic_refresh_bitrate(const AV1_COMMON *cm, - const RATE_CONTROL *rc) { - // Turn off cyclic refresh if bits available per frame is not sufficiently - // larger than bit cost of segmentation. Segment map bit cost should scale - // with number of seg blocks, so compare available bits to number of blocks. - // Average bits available per frame = avg_frame_bandwidth - // Number of (8x8) blocks in frame = mi_rows * mi_cols; - const float factor = 0.25; - const int number_blocks = cm->mi_rows * cm->mi_cols; - // The condition below corresponds to turning off at target bitrates: - // (at 30fps), ~12kbps for CIF, 36kbps for VGA, 100kps for HD/720p. - // Also turn off at very small frame sizes, to avoid too large fraction of - // superblocks to be refreshed per frame. Threshold below is less than QCIF. - if (rc->avg_frame_bandwidth < factor * number_blocks || - number_blocks / 64 < 5) - return 0; - else - return 1; -} - // Check if this coding block, of size bsize, should be considered for refresh // (lower-qp coding). Decision can be based on various factors, such as // size of the coding block (i.e., below min_block size rejected), coding @@ -158,11 +139,11 @@ int av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi, const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; int estimated_bits; int mbs = cm->MBs; - int num8x8bl = mbs << 2; + int num4x4bl = mbs << 4; // Weight for non-base segments: use actual number of blocks refreshed in - // previous/just encoded frame. Note number of blocks here is in 8x8 units. - double weight_segment1 = (double)cr->actual_num_seg1_blocks / num8x8bl; - double weight_segment2 = (double)cr->actual_num_seg2_blocks / num8x8bl; + // previous/just encoded frame. Note number of blocks here is in 4x4 units. + double weight_segment1 = (double)cr->actual_num_seg1_blocks / num4x4bl; + double weight_segment2 = (double)cr->actual_num_seg2_blocks / num4x4bl; // Take segment weighted average for estimated bits. estimated_bits = (int)((1.0 - weight_segment1 - weight_segment2) * @@ -190,14 +171,14 @@ int av1_cyclic_refresh_rc_bits_per_mb(const AV1_COMP *cpi, int i, const AV1_COMMON *const cm = &cpi->common; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; int bits_per_mb; - int num8x8bl = cm->MBs << 2; + int num4x4bl = cm->MBs << 4; // Weight for segment prior to encoding: take the average of the target // number for the frame to be encoded and the actual from the previous frame. double weight_segment = (double)((cr->target_num_seg_blocks + cr->actual_num_seg1_blocks + cr->actual_num_seg2_blocks) >> 1) / - num8x8bl; + num4x4bl; // Compute delta-q corresponding to qindex i. int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta); // Take segment weighted average for bits per mb. @@ -264,21 +245,6 @@ void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, int map_offset = block_index + y * cm->mi_cols + x; cr->map[map_offset] = new_map_value; cpi->segmentation_map[map_offset] = mbmi->segment_id; - // Inter skip blocks were clearly not coded at the current qindex, so - // don't update the map for them. For cases where motion is non-zero or - // the reference frame isn't the previous frame, the previous value in - // the map for this spatial location is not entirely correct. - if ((!is_inter_block(mbmi) || !skip) && - mbmi->segment_id <= CR_SEGMENT_ID_BOOST2) { - cr->last_coded_q_map[map_offset] = clamp( - cm->base_qindex + cr->qindex_delta[mbmi->segment_id], 0, MAXQ); - } else if (is_inter_block(mbmi) && skip && - mbmi->segment_id <= CR_SEGMENT_ID_BOOST2) { - cr->last_coded_q_map[map_offset] = - AOMMIN(clamp(cm->base_qindex + cr->qindex_delta[mbmi->segment_id], - 0, MAXQ), - cr->last_coded_q_map[map_offset]); - } } } @@ -315,73 +281,6 @@ void av1_cyclic_refresh_set_golden_update(AV1_COMP *const cpi) { rc->baseline_gf_interval = 40; } -// Update some encoding stats (from the just encoded frame). If this frame's -// background has high motion, refresh the golden frame. Otherwise, if the -// golden reference is to be updated check if we should NOT update the golden -// ref. -void av1_cyclic_refresh_check_golden_update(AV1_COMP *const cpi) { - AV1_COMMON *const cm = &cpi->common; - CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; - int mi_row, mi_col; - double fraction_low = 0.0; - int low_content_frame = 0; - - MB_MODE_INFO **mi; - RATE_CONTROL *const rc = &cpi->rc; - const int rows = cm->mi_rows, cols = cm->mi_cols; - int cnt1 = 0, cnt2 = 0; - int force_gf_refresh = 0; - - for (mi_row = 0; mi_row < rows; mi_row++) { - mi = cm->mi_grid_visible + mi_row * cm->mi_stride; - - for (mi_col = 0; mi_col < cols; mi_col++) { - int16_t abs_mvr = mi[0]->mv[0].as_mv.row >= 0 - ? mi[0]->mv[0].as_mv.row - : -1 * mi[0]->mv[0].as_mv.row; - int16_t abs_mvc = mi[0]->mv[0].as_mv.col >= 0 - ? mi[0]->mv[0].as_mv.col - : -1 * mi[0]->mv[0].as_mv.col; - - // Calculate the motion of the background. - if (abs_mvr <= 16 && abs_mvc <= 16) { - cnt1++; - if (abs_mvr == 0 && abs_mvc == 0) cnt2++; - } - mi++; - - // Accumulate low_content_frame. - if (cr->map[mi_row * cols + mi_col] < 1) low_content_frame++; - } - } - - // For video conference clips, if the background has high motion in current - // frame because of the camera movement, set this frame as the golden frame. - // Use 70% and 5% as the thresholds for golden frame refreshing. - if (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1) { - av1_cyclic_refresh_set_golden_update(cpi); - rc->frames_till_gf_update_due = rc->baseline_gf_interval; - - if (rc->frames_till_gf_update_due > rc->frames_to_key) - rc->frames_till_gf_update_due = rc->frames_to_key; - cpi->refresh_golden_frame = 1; - force_gf_refresh = 1; - } - - fraction_low = (double)low_content_frame / (rows * cols); - // Update average. - cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4; - if (!force_gf_refresh && cpi->refresh_golden_frame == 1) { - // Don't update golden reference if the amount of low_content for the - // current encoded frame is small, or if the recursive average of the - // low_content over the update interval window falls below threshold. - if (fraction_low < 0.8 || cr->low_content_avg < 0.7) - cpi->refresh_golden_frame = 0; - // Reset for next internal. - cr->low_content_avg = fraction_low; - } -} - // Update the segmentation map, and related quantities: cyclic refresh map, // refresh sb_index, and target number of blocks to be refreshed. // The map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or to @@ -458,26 +357,70 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { // Set cyclic refresh parameters. void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { + // TODO(marpan): Parameters need to be tuned. const RATE_CONTROL *const rc = &cpi->rc; const AV1_COMMON *const cm = &cpi->common; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; + int num4x4bl = cm->MBs << 4; + int target_refresh = 0; + double weight_segment_target = 0; + double weight_segment = 0; + int qp_thresh = AOMMIN(20, rc->best_quality << 1); + cr->apply_cyclic_refresh = 1; + if (frame_is_intra_only(cm) || is_lossless_requested(&cpi->oxcf) || + rc->avg_frame_qindex[INTER_FRAME] < qp_thresh) { + cr->apply_cyclic_refresh = 0; + return; + } cr->percent_refresh = 10; - cr->max_qdelta_perc = 50; + cr->max_qdelta_perc = 60; cr->time_for_refresh = 0; + cr->motion_thresh = 32; + cr->rate_boost_fac = 15; // Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4) // periods of the refresh cycle, after a key frame. - if (rc->frames_since_key < 4 * cr->percent_refresh) + // Account for larger interval on base layer for temporal layers. + if (cr->percent_refresh > 0 && + rc->frames_since_key < 400 / cr->percent_refresh) { cr->rate_ratio_qdelta = 3.0; - else - cr->rate_ratio_qdelta = 2.0; - // Adjust some parameters for low resolutions at low bitrates. - if (cm->width <= 352 && cm->height <= 288 && rc->avg_frame_bandwidth < 3400) { - cr->motion_thresh = 4; - cr->rate_boost_fac = 10; } else { - cr->motion_thresh = 32; - cr->rate_boost_fac = 17; + cr->rate_ratio_qdelta = 2.0; } + // Adjust some parameters for low resolutions. + if (cm->width <= 352 && cm->height <= 288) { + if (rc->avg_frame_bandwidth < 3000) { + cr->motion_thresh = 16; + cr->rate_boost_fac = 13; + } else { + cr->max_qdelta_perc = 70; + cr->rate_ratio_qdelta = AOMMAX(cr->rate_ratio_qdelta, 2.5); + } + } + if (cpi->oxcf.rc_mode == AOM_VBR) { + // To be adjusted for VBR mode, e.g., based on gf period and boost. + // For now use smaller qp-delta (than CBR), no second boosted seg, and + // turn-off (no refresh) on golden refresh (since it's already boosted). + cr->percent_refresh = 10; + cr->rate_ratio_qdelta = 1.5; + cr->rate_boost_fac = 10; + if (cpi->refresh_golden_frame == 1) { + cr->percent_refresh = 0; + cr->rate_ratio_qdelta = 1.0; + } + } + // Weight for segment prior to encoding: take the average of the target + // number for the frame to be encoded and the actual from the previous frame. + // Use the target if its less. To be used for setting the base qp for the + // frame in vp9_rc_regulate_q. + target_refresh = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100; + weight_segment_target = (double)(target_refresh) / num4x4bl; + weight_segment = (double)((target_refresh + cr->actual_num_seg1_blocks + + cr->actual_num_seg2_blocks) >> + 1) / + num4x4bl; + if (weight_segment_target < 7 * weight_segment / 8) + weight_segment = weight_segment_target; + cr->weight_segment = weight_segment; } // Setup cyclic background refresh: set delta q and segmentation map. @@ -486,7 +429,6 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { const RATE_CONTROL *const rc = &cpi->rc; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; struct segmentation *const seg = &cm->seg; - const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc); int resolution_change = cm->prev_frame && (cm->width != cm->prev_frame->width || cm->height != cm->prev_frame->height); @@ -498,8 +440,7 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { return; } if (cm->current_frame.frame_number == 0) cr->low_content_avg = 0.0; - // Don't apply refresh on key frame or enhancement layer frames. - if (!apply_cyclic_refresh || cm->current_frame.frame_type == KEY_FRAME) { + if (!cr->apply_cyclic_refresh) { // Set segmentation map to 0 and disable. unsigned char *const seg_map = cpi->segmentation_map; memset(seg_map, 0, cm->mi_rows * cm->mi_cols); diff --git a/third_party/aom/av1/encoder/aq_cyclicrefresh.h b/third_party/aom/av1/encoder/aq_cyclicrefresh.h index b45781983d..ddabae6121 100644 --- a/third_party/aom/av1/encoder/aq_cyclicrefresh.h +++ b/third_party/aom/av1/encoder/aq_cyclicrefresh.h @@ -54,19 +54,12 @@ void av1_cyclic_refresh_update_segment(const struct AV1_COMP *cpi, int mi_col, BLOCK_SIZE bsize, int64_t rate, int64_t dist, int skip); -// Update the segmentation map, and related quantities: cyclic refresh map, -// refresh sb_index, and target number of blocks to be refreshed. -void av1_cyclic_refresh_update__map(struct AV1_COMP *const cpi); - // Update the actual number of blocks that were applied the segment delta q. void av1_cyclic_refresh_postencode(struct AV1_COMP *const cpi); // Set golden frame update interval, for 1 pass CBR mode. void av1_cyclic_refresh_set_golden_update(struct AV1_COMP *const cpi); -// Check if we should not update golden reference, based on past refresh stats. -void av1_cyclic_refresh_check_golden_update(struct AV1_COMP *const cpi); - // Set/update global/frame level refresh parameters. void av1_cyclic_refresh_update_parameters(struct AV1_COMP *const cpi); diff --git a/third_party/aom/av1/encoder/av1_quantize.c b/third_party/aom/av1/encoder/av1_quantize.c index 162724b4c3..ff1342c0ff 100644 --- a/third_party/aom/av1/encoder/av1_quantize.c +++ b/third_party/aom/av1/encoder/av1_quantize.c @@ -276,13 +276,13 @@ void av1_quantize_b_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs, } else { switch (qparam->log_scale) { case 0: - aom_quantize_b_adaptive_c( - coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX, - p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX, - eob_ptr, sc->scan, sc->iscan); + aom_quantize_b_adaptive(coeff_ptr, n_coeffs, p->zbin_QTX, + p->round_QTX, p->quant_QTX, + p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, + p->dequant_QTX, eob_ptr, sc->scan, sc->iscan); break; case 1: - aom_quantize_b_32x32_adaptive_c( + aom_quantize_b_32x32_adaptive( coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX, p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX, eob_ptr, sc->scan, sc->iscan); diff --git a/third_party/aom/av1/encoder/av1_quantize.h b/third_party/aom/av1/encoder/av1_quantize.h index c709234956..64192653eb 100644 --- a/third_party/aom/av1/encoder/av1_quantize.h +++ b/third_party/aom/av1/encoder/av1_quantize.h @@ -22,6 +22,9 @@ extern "C" { #endif +#define EOB_FACTOR 325 +#define SKIP_EOB_FACTOR_ADJUST 200 + typedef struct QUANT_PARAM { int log_scale; TX_SIZE tx_size; diff --git a/third_party/aom/av1/encoder/bitstream.c b/third_party/aom/av1/encoder/bitstream.c index 3140551e9c..cbac2b26a7 100644 --- a/third_party/aom/av1/encoder/bitstream.c +++ b/third_party/aom/av1/encoder/bitstream.c @@ -369,10 +369,18 @@ static void pack_txb_tokens(aom_writer *w, AV1_COMMON *cm, MACROBLOCK *const x, blk_col)]; if (tx_size == plane_tx_size || plane) { - tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block); - const uint16_t eob = x->mbmi_ext->eobs[plane][block]; - TXB_CTX txb_ctx = { x->mbmi_ext->txb_skip_ctx[plane][block], - x->mbmi_ext->dc_sign_ctx[plane][block] }; + const int txb_offset = + x->mbmi_ext->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN); + tran_low_t *tcoeff_txb = + x->mbmi_ext->cb_coef_buff->tcoeff[plane] + x->mbmi_ext->cb_offset; + uint16_t *eob_txb = x->mbmi_ext->cb_coef_buff->eobs[plane] + txb_offset; + uint8_t *txb_skip_ctx_txb = + x->mbmi_ext->cb_coef_buff->txb_skip_ctx[plane] + txb_offset; + int *dc_sign_ctx_txb = + x->mbmi_ext->cb_coef_buff->dc_sign_ctx[plane] + txb_offset; + tran_low_t *tcoeff = BLOCK_OFFSET(tcoeff_txb, block); + const uint16_t eob = eob_txb[block]; + TXB_CTX txb_ctx = { txb_skip_ctx_txb[block], dc_sign_ctx_txb[block] }; av1_write_coeffs_txb(cm, xd, w, blk_row, blk_col, plane, tx_size, tcoeff, eob, &txb_ctx); #if CONFIG_RD_DEBUG @@ -627,7 +635,7 @@ static void write_mb_interp_filter(AV1_COMP *cpi, const MACROBLOCKD *xd, av1_extract_interp_filter(mbmi->interp_filters, dir); aom_write_symbol(w, filter, ec_ctx->switchable_interp_cdf[ctx], SWITCHABLE_FILTERS); - ++cpi->interp_filter_selected[0][filter]; + ++cm->cur_frame->interp_filter_selected[filter]; if (cm->seq_params.enable_dual_filter == 0) return; } } @@ -1162,9 +1170,9 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, mbmi->interinter_comp.type == COMPOUND_DIFFWTD); if (is_interinter_compound_used(COMPOUND_WEDGE, bsize)) - aom_write_symbol(w, mbmi->interinter_comp.type - 1, + aom_write_symbol(w, mbmi->interinter_comp.type - COMPOUND_WEDGE, ec_ctx->compound_type_cdf[bsize], - COMPOUND_TYPES - 1); + MASKED_COMPOUND_TYPES); if (mbmi->interinter_comp.type == COMPOUND_WEDGE) { assert(is_interinter_compound_used(COMPOUND_WEDGE, bsize)); @@ -1288,7 +1296,7 @@ static void enc_dump_logs(AV1_COMP *cpi, int mi_row, int mi_col) { } const int16_t mode_ctx = - is_comp_ref ? mbmi_ext->compound_mode_context[mbmi->ref_frame[0]] + is_comp_ref ? 0 : av1_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame); @@ -2743,21 +2751,14 @@ static int check_frame_refs_short_signaling(AV1_COMMON *const cm) { // Check whether the encoder side ref frame choices are aligned with that to // be derived at the decoder side. - int remapped_ref_idx_copy[REF_FRAMES]; - struct scale_factors ref_scale_factors_copy[REF_FRAMES]; - - // Backup the frame refs info - memcpy(remapped_ref_idx_copy, cm->remapped_ref_idx, - REF_FRAMES * sizeof(*remapped_ref_idx_copy)); - memcpy(ref_scale_factors_copy, cm->ref_scale_factors, - REF_FRAMES * sizeof(*ref_scale_factors_copy)); + int remapped_ref_idx_decoder[REF_FRAMES]; const int lst_map_idx = get_ref_frame_map_idx(cm, LAST_FRAME); const int gld_map_idx = get_ref_frame_map_idx(cm, GOLDEN_FRAME); // Set up the frame refs mapping indexes according to the // frame_refs_short_signaling policy. - av1_set_frame_refs(cm, lst_map_idx, gld_map_idx); + av1_set_frame_refs(cm, remapped_ref_idx_decoder, lst_map_idx, gld_map_idx); // We only turn on frame_refs_short_signaling when the encoder side decision // on ref frames is identical to that at the decoder side. @@ -2765,10 +2766,11 @@ static int check_frame_refs_short_signaling(AV1_COMMON *const cm) { for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ++ref_idx) { // Compare the buffer index between two reference frames indexed // respectively by the encoder and the decoder side decisions. - RefCntBuffer *ref_frame_buf_copy = NULL; - if (remapped_ref_idx_copy[ref_idx] != INVALID_IDX) - ref_frame_buf_copy = cm->ref_frame_map[remapped_ref_idx_copy[ref_idx]]; - if (get_ref_frame_buf(cm, LAST_FRAME + ref_idx) != ref_frame_buf_copy) { + RefCntBuffer *ref_frame_buf_new = NULL; + if (remapped_ref_idx_decoder[ref_idx] != INVALID_IDX) { + ref_frame_buf_new = cm->ref_frame_map[remapped_ref_idx_decoder[ref_idx]]; + } + if (get_ref_frame_buf(cm, LAST_FRAME + ref_idx) != ref_frame_buf_new) { frame_refs_short_signaling = 0; break; } @@ -2786,13 +2788,6 @@ static int check_frame_refs_short_signaling(AV1_COMMON *const cm) { } #endif // 0 - // Restore the frame refs info if frame_refs_short_signaling is off. - if (!frame_refs_short_signaling) { - memcpy(cm->remapped_ref_idx, remapped_ref_idx_copy, - REF_FRAMES * sizeof(*remapped_ref_idx_copy)); - memcpy(cm->ref_scale_factors, ref_scale_factors_copy, - REF_FRAMES * sizeof(*ref_scale_factors_copy)); - } return frame_refs_short_signaling; } @@ -2805,6 +2800,8 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi, MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; CurrentFrame *const current_frame = &cm->current_frame; + current_frame->frame_refs_short_signaling = 0; + if (seq_params->still_picture) { assert(cm->show_existing_frame == 0); assert(cm->show_frame == 1); @@ -2867,24 +2864,25 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi, int frame_size_override_flag = 0; if (seq_params->reduced_still_picture_hdr) { - assert(cm->width == seq_params->max_frame_width && - cm->height == seq_params->max_frame_height); + assert(cm->superres_upscaled_width == seq_params->max_frame_width && + cm->superres_upscaled_height == seq_params->max_frame_height); } else { if (seq_params->frame_id_numbers_present_flag) { int frame_id_len = seq_params->frame_id_length; aom_wb_write_literal(wb, cm->current_frame_id, frame_id_len); } - if (cm->width > seq_params->max_frame_width || - cm->height > seq_params->max_frame_height) { + if (cm->superres_upscaled_width > seq_params->max_frame_width || + cm->superres_upscaled_height > seq_params->max_frame_height) { aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, "Frame dimensions are larger than the maximum values"); } frame_size_override_flag = - frame_is_sframe(cm) ? 1 - : (cm->width != seq_params->max_frame_width || - cm->height != seq_params->max_frame_height); + frame_is_sframe(cm) + ? 1 + : (cm->superres_upscaled_width != seq_params->max_frame_width || + cm->superres_upscaled_height != seq_params->max_frame_height); if (!frame_is_sframe(cm)) aom_wb_write_bit(wb, frame_size_override_flag); if (seq_params->order_hint_info.enable_order_hint) @@ -2960,25 +2958,25 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi, // NOTE: Error resilient mode turns off frame_refs_short_signaling // automatically. - int frame_refs_short_signaling = 0; #define FRAME_REFS_SHORT_SIGNALING 0 #if FRAME_REFS_SHORT_SIGNALING - frame_refs_short_signaling = + current_frame->frame_refs_short_signaling = seq_params->order_hint_info.enable_order_hint; #endif // FRAME_REFS_SHORT_SIGNALING - if (frame_refs_short_signaling) { + if (current_frame->frame_refs_short_signaling) { // NOTE(zoeliu@google.com): // An example solution for encoder-side implementation on frame refs // short signaling, which is only turned on when the encoder side // decision on ref frames is identical to that at the decoder side. - frame_refs_short_signaling = check_frame_refs_short_signaling(cm); + current_frame->frame_refs_short_signaling = + check_frame_refs_short_signaling(cm); } if (seq_params->order_hint_info.enable_order_hint) - aom_wb_write_bit(wb, frame_refs_short_signaling); + aom_wb_write_bit(wb, current_frame->frame_refs_short_signaling); - if (frame_refs_short_signaling) { + if (current_frame->frame_refs_short_signaling) { const int lst_ref = get_ref_frame_map_idx(cm, LAST_FRAME); aom_wb_write_literal(wb, lst_ref, REF_FRAMES_LOG2); @@ -2988,7 +2986,7 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi, for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { assert(get_ref_frame_map_idx(cm, ref_frame) != INVALID_IDX); - if (!frame_refs_short_signaling) + if (!current_frame->frame_refs_short_signaling) aom_wb_write_literal(wb, get_ref_frame_map_idx(cm, ref_frame), REF_FRAMES_LOG2); if (seq_params->frame_id_numbers_present_flag) { @@ -3236,8 +3234,12 @@ static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst, return wpos; } -uint32_t write_obu_header(OBU_TYPE obu_type, int obu_extension, - uint8_t *const dst) { +uint32_t av1_write_obu_header(AV1_COMP *const cpi, OBU_TYPE obu_type, + int obu_extension, uint8_t *const dst) { + if (cpi->keep_level_stats && + (obu_type == OBU_FRAME || obu_type == OBU_FRAME_HEADER)) + ++cpi->frame_header_count; + struct aom_write_bit_buffer wb = { dst, 0 }; uint32_t size = 0; @@ -3289,9 +3291,8 @@ static void add_trailing_bits(struct aom_write_bit_buffer *wb) { } } -static void write_bitstream_level(BitstreamLevel bl, +static void write_bitstream_level(AV1_LEVEL seq_level_idx, struct aom_write_bit_buffer *wb) { - uint8_t seq_level_idx = major_minor_to_seq_level_idx(bl); assert(is_valid_seq_level_idx(seq_level_idx)); aom_wb_write_literal(wb, seq_level_idx, LEVEL_BITS); } @@ -3314,7 +3315,7 @@ uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst) { assert(cm->timing_info_present == 0); assert(cm->seq_params.decoder_model_info_present_flag == 0); assert(cm->seq_params.display_model_info_present_flag == 0); - write_bitstream_level(cm->seq_params.level[0], &wb); + write_bitstream_level(cm->seq_params.seq_level_idx[0], &wb); } else { aom_wb_write_bit(&wb, cm->timing_info_present); // timing info present flag @@ -3333,8 +3334,8 @@ uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst) { for (i = 0; i < cm->seq_params.operating_points_cnt_minus_1 + 1; i++) { aom_wb_write_literal(&wb, cm->seq_params.operating_point_idc[i], OP_POINTS_IDC_BITS); - write_bitstream_level(cm->seq_params.level[i], &wb); - if (cm->seq_params.level[i].major > 3) + write_bitstream_level(cm->seq_params.seq_level_idx[i], &wb); + if (cm->seq_params.seq_level_idx[i] >= SEQ_LEVEL_4_0) aom_wb_write_bit(&wb, cm->seq_params.tier[i]); if (cm->seq_params.decoder_model_info_present_flag) { aom_wb_write_bit(&wb, @@ -3436,7 +3437,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, // For large_scale_tile case, we always have only one tile group, so it can // be written as an OBU_FRAME. const OBU_TYPE obu_type = OBU_FRAME; - const uint32_t tg_hdr_size = write_obu_header(obu_type, 0, data); + const uint32_t tg_hdr_size = av1_write_obu_header(cpi, obu_type, 0, data); data += tg_hdr_size; const uint32_t frame_header_size = @@ -3591,7 +3592,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, const OBU_TYPE obu_type = (num_tg_hdrs == 1) ? OBU_FRAME : OBU_TILE_GROUP; curr_tg_data_size = - write_obu_header(obu_type, obu_extension_header, data); + av1_write_obu_header(cpi, obu_type, obu_extension_header, data); obu_header_size = curr_tg_data_size; if (num_tg_hdrs == 1) { @@ -3677,8 +3678,9 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, // Rewrite the OBU header to change the OBU type to Redundant Frame // Header. - write_obu_header(OBU_REDUNDANT_FRAME_HEADER, obu_extension_header, - &data[fh_info->obu_header_byte_offset]); + av1_write_obu_header(cpi, OBU_REDUNDANT_FRAME_HEADER, + obu_extension_header, + &data[fh_info->obu_header_byte_offset]); data += fh_info->total_length; @@ -3757,11 +3759,13 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, bitstream_queue_reset_write(); #endif + cpi->frame_header_count = 0; + // The TD is now written outside the frame encode loop // write sequence header obu if KEY_FRAME, preceded by 4-byte size if (cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) { - obu_header_size = write_obu_header(OBU_SEQUENCE_HEADER, 0, data); + obu_header_size = av1_write_obu_header(cpi, OBU_SEQUENCE_HEADER, 0, data); obu_payload_size = write_sequence_header_obu(cpi, data + obu_header_size); const size_t length_field_size = @@ -3781,7 +3785,7 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, // Write Frame Header OBU. fh_info.frame_header = data; obu_header_size = - write_obu_header(OBU_FRAME_HEADER, obu_extension_header, data); + av1_write_obu_header(cpi, OBU_FRAME_HEADER, obu_extension_header, data); obu_payload_size = write_frame_header_obu(cpi, &saved_wb, data + obu_header_size, 1); diff --git a/third_party/aom/av1/encoder/bitstream.h b/third_party/aom/av1/encoder/bitstream.h index a567086e95..b05d0d50df 100644 --- a/third_party/aom/av1/encoder/bitstream.h +++ b/third_party/aom/av1/encoder/bitstream.h @@ -27,8 +27,8 @@ uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst); // Writes the OBU header byte, and the OBU header extension byte when // 'obu_extension' is non-zero. Returns number of bytes written to 'dst'. -uint32_t write_obu_header(OBU_TYPE obu_type, int obu_extension, - uint8_t *const dst); +uint32_t av1_write_obu_header(AV1_COMP *const cpi, OBU_TYPE obu_type, + int obu_extension, uint8_t *const dst); int write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size, uint8_t *dest); @@ -36,11 +36,6 @@ int write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size, int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, int *const largest_tile_id); -static INLINE int av1_preserve_existing_gf(const AV1_COMP *const cpi) { - // Do not swap gf and arf indices for internal overlay frames - return cpi->rc.is_src_frame_alt_ref && !cpi->rc.is_src_frame_ext_arf; -} - void av1_write_tx_type(const AV1_COMMON *const cm, const MACROBLOCKD *xd, int blk_row, int blk_col, int plane, TX_SIZE tx_size, aom_writer *w); diff --git a/third_party/aom/av1/encoder/block.h b/third_party/aom/av1/encoder/block.h index 87761e9065..96b0991dde 100644 --- a/third_party/aom/av1/encoder/block.h +++ b/third_party/aom/av1/encoder/block.h @@ -75,13 +75,10 @@ typedef struct { typedef struct { // TODO(angiebird): Reduce the buffer size according to sb_type - tran_low_t *tcoeff[MAX_MB_PLANE]; - uint16_t *eobs[MAX_MB_PLANE]; - uint8_t *txb_skip_ctx[MAX_MB_PLANE]; - int *dc_sign_ctx[MAX_MB_PLANE]; + CB_COEFF_BUFFER *cb_coef_buff; CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE]; int_mv global_mvs[REF_FRAMES]; - int16_t compound_mode_context[MODE_CTX_REF_FRAMES]; + int cb_offset; int16_t mode_context[MODE_CTX_REF_FRAMES]; uint8_t ref_mv_count[MODE_CTX_REF_FRAMES]; } MB_MODE_INFO_EXT; @@ -156,7 +153,7 @@ typedef struct { // Region size for mode decision sampling in the first pass of partition // search(two_pass_partition_search speed feature), in units of mi size(4). -// Used by the mode_pruning_based_on_two_pass_partition_search speed feature. +// Used by the mode pruning in two_pass_partition_search feature. #define FIRST_PARTITION_PASS_SAMPLE_REGION 8 #define FIRST_PARTITION_PASS_SAMPLE_REGION_LOG2 3 #define FIRST_PARTITION_PASS_STATS_TABLES \ @@ -177,6 +174,8 @@ typedef struct { uint8_t ref0_counts[REF_FRAMES]; // Counters for ref_frame[0]. uint8_t ref1_counts[REF_FRAMES]; // Counters for ref_frame[1]. int sample_counts; // Number of samples collected. + uint8_t interintra_motion_mode_count[REF_FRAMES]; // Counter for interintra + // motion mode } FIRST_PARTITION_PASS_STATS; #define MAX_INTERP_FILTER_STATS 64 @@ -185,12 +184,17 @@ typedef struct { int_mv mv[2]; int8_t ref_frames[2]; COMPOUND_TYPE comp_type; + int64_t rd; + int skip_txfm_sb; + int64_t skip_sse_sb; + unsigned int pred_sse; } INTERPOLATION_FILTER_STATS; #define MAX_COMP_RD_STATS 64 typedef struct { int32_t rate[COMPOUND_TYPES]; int64_t dist[COMPOUND_TYPES]; + int64_t comp_model_rd[COMPOUND_TYPES]; int_mv mv[2]; MV_REFERENCE_FRAME ref_frames[2]; PREDICTION_MODE mode; @@ -272,6 +276,7 @@ struct macroblock { unsigned int max_mv_context[REF_FRAMES]; unsigned int source_variance; + unsigned int simple_motion_pred_sse; unsigned int pred_sse[REF_FRAMES]; int pred_mv_sad[REF_FRAMES]; @@ -351,7 +356,7 @@ struct macroblock { // BWDREF_FRAME) in bidir-comp mode. int comp_bwdref_cost[REF_CONTEXTS][BWD_REFS - 1][2]; int inter_compound_mode_cost[INTER_MODE_CONTEXTS][INTER_COMPOUND_MODES]; - int compound_type_cost[BLOCK_SIZES_ALL][COMPOUND_TYPES - 1]; + int compound_type_cost[BLOCK_SIZES_ALL][MASKED_COMPOUND_TYPES]; int wedge_idx_cost[BLOCK_SIZES_ALL][16]; int interintra_cost[BLOCK_SIZE_GROUPS][2]; int wedge_interintra_cost[BLOCK_SIZES_ALL][2]; @@ -396,6 +401,11 @@ struct macroblock { // Store the fractional best motion vector during sub/Qpel-pixel motion search int_mv fractional_best_mv[3]; + // Ref frames that are selected by square partition blocks within a super- + // block, in MI resolution. They can be used to prune ref frames for + // rectangular blocks. + int picked_ref_frames_mask[32 * 32]; + // use default transform and skip transform type search for intra modes int use_default_intra_tx_type; // use default transform and skip transform type search for inter modes @@ -416,6 +426,9 @@ struct macroblock { // detection). For reference, 556 is the value returned for a solid // vertical black/white edge. uint16_t edge_strength; + // The strongest edge strength seen along the x/y axis. + uint16_t edge_strength_x; + uint16_t edge_strength_y; // [Saved stat index] COMP_RD_STATS comp_rd_stats[MAX_COMP_RD_STATS]; diff --git a/third_party/aom/av1/encoder/context_tree.h b/third_party/aom/av1/encoder/context_tree.h index 66f24f958e..205ac8ad3d 100644 --- a/third_party/aom/av1/encoder/context_tree.h +++ b/third_party/aom/av1/encoder/context_tree.h @@ -58,8 +58,6 @@ typedef struct { int hybrid_pred_diff; int comp_pred_diff; int single_pred_diff; - // Skip certain ref frames during RD search of rectangular partitions. - int skip_ref_frame_mask; // TODO(jingning) Use RD_COST struct here instead. This involves a boarder // scope of refactoring. @@ -67,26 +65,12 @@ typedef struct { int rd_mode_is_ready; // Flag to indicate whether rd pick mode decision has // been made. - int mode_selected; -#if CONFIG_ONE_PASS_SVM - // Features for one pass svm early term - int seg_feat; -#endif // motion vector cache for adaptive motion search control in partition // search loop MV pred_mv[REF_FRAMES]; InterpFilter pred_interp_filter; PARTITION_TYPE partition; - - // Reference and prediction mode cache for ref/mode speedup - // TODO(zoeliu@gmail.com): The values of ref_selected and mode_selected will - // be explored for further encoder speedup, to differentiate this approach for - // setting skip_ref_frame_mask from others. For instance, it is possible that - // the underlying square block(s) share the same SIMPLE_TRANSLATION motion - // mode as well as the mode of GLOBALMV, more ref/mode combos could be - // skipped. - MV_REFERENCE_FRAME ref_selected[2]; } PICK_MODE_CONTEXT; typedef struct { diff --git a/third_party/aom/av1/encoder/encode_strategy.c b/third_party/aom/av1/encoder/encode_strategy.c index cc933487d0..e9d6ee7707 100644 --- a/third_party/aom/av1/encoder/encode_strategy.c +++ b/third_party/aom/av1/encoder/encode_strategy.c @@ -28,126 +28,109 @@ #include "av1/encoder/encoder.h" #include "av1/encoder/encode_strategy.h" #include "av1/encoder/firstpass.h" +#include "av1/encoder/pass2_strategy.h" #include "av1/encoder/temporal_filter.h" #include "av1/encoder/tpl_model.h" -// Define the reference buffers that will be updated post encode. -void av1_configure_buffer_updates(AV1_COMP *cpi, const FRAME_UPDATE_TYPE type) { +void av1_configure_buffer_updates(AV1_COMP *const cpi, + EncodeFrameParams *const frame_params, + const FRAME_UPDATE_TYPE type, + int force_refresh_all) { // NOTE(weitinglin): Should we define another function to take care of // cpi->rc.is_$Source_Type to make this function as it is in the comment? - // show_existing_frame is a flag left set from the end of encoding the - // previous frame. Alongside it, is_src_frame_alt_ref may also be left - // set so shouldn't be cleared in this case. - if (!cpi->common.show_existing_frame) cpi->rc.is_src_frame_alt_ref = 0; - - cpi->rc.is_bwd_ref_frame = 0; - cpi->rc.is_last_bipred_frame = 0; - cpi->rc.is_bipred_frame = 0; - cpi->rc.is_src_frame_ext_arf = 0; + cpi->rc.is_src_frame_alt_ref = 0; + cpi->rc.is_src_frame_internal_arf = 0; switch (type) { case KF_UPDATE: - cpi->refresh_last_frame = 1; - cpi->refresh_golden_frame = 1; - cpi->refresh_bwd_ref_frame = 1; - cpi->refresh_alt2_ref_frame = 1; - cpi->refresh_alt_ref_frame = 1; + frame_params->refresh_last_frame = 1; + frame_params->refresh_golden_frame = 1; + frame_params->refresh_bwd_ref_frame = 1; + frame_params->refresh_alt2_ref_frame = 1; + frame_params->refresh_alt_ref_frame = 1; break; case LF_UPDATE: - cpi->refresh_last_frame = 1; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; + frame_params->refresh_last_frame = 1; + frame_params->refresh_golden_frame = 0; + frame_params->refresh_bwd_ref_frame = 0; + frame_params->refresh_alt2_ref_frame = 0; + frame_params->refresh_alt_ref_frame = 0; break; case GF_UPDATE: // TODO(zoeliu): To further investigate whether 'refresh_last_frame' is // needed. - cpi->refresh_last_frame = 1; - cpi->refresh_golden_frame = 1; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; + frame_params->refresh_last_frame = 1; + frame_params->refresh_golden_frame = 1; + frame_params->refresh_bwd_ref_frame = 0; + frame_params->refresh_alt2_ref_frame = 0; + frame_params->refresh_alt_ref_frame = 0; break; case OVERLAY_UPDATE: - cpi->refresh_last_frame = 0; - cpi->refresh_golden_frame = 1; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; + frame_params->refresh_last_frame = 0; + frame_params->refresh_golden_frame = 1; + frame_params->refresh_bwd_ref_frame = 0; + frame_params->refresh_alt2_ref_frame = 0; + frame_params->refresh_alt_ref_frame = 0; cpi->rc.is_src_frame_alt_ref = 1; break; case ARF_UPDATE: - cpi->refresh_last_frame = 0; - cpi->refresh_golden_frame = 0; + frame_params->refresh_last_frame = 0; + frame_params->refresh_golden_frame = 0; // NOTE: BWDREF does not get updated along with ALTREF_FRAME. - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 1; - break; - - case BRF_UPDATE: - cpi->refresh_last_frame = 0; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 1; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; - - cpi->rc.is_bwd_ref_frame = 1; - break; - - case LAST_BIPRED_UPDATE: - cpi->refresh_last_frame = 1; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; - - cpi->rc.is_last_bipred_frame = 1; - break; - - case BIPRED_UPDATE: - cpi->refresh_last_frame = 1; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; - - cpi->rc.is_bipred_frame = 1; + frame_params->refresh_bwd_ref_frame = 0; + frame_params->refresh_alt2_ref_frame = 0; + frame_params->refresh_alt_ref_frame = 1; break; case INTNL_OVERLAY_UPDATE: - cpi->refresh_last_frame = 1; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; + frame_params->refresh_last_frame = 1; + frame_params->refresh_golden_frame = 0; + frame_params->refresh_bwd_ref_frame = 0; + frame_params->refresh_alt2_ref_frame = 0; + frame_params->refresh_alt_ref_frame = 0; cpi->rc.is_src_frame_alt_ref = 1; - cpi->rc.is_src_frame_ext_arf = 1; + cpi->rc.is_src_frame_internal_arf = 1; break; case INTNL_ARF_UPDATE: - cpi->refresh_last_frame = 0; - cpi->refresh_golden_frame = 0; - if (cpi->new_bwdref_update_rule == 1 && cpi->oxcf.pass == 2) { - cpi->refresh_bwd_ref_frame = 1; - cpi->refresh_alt2_ref_frame = 0; + frame_params->refresh_last_frame = 0; + frame_params->refresh_golden_frame = 0; + if (cpi->oxcf.pass == 2) { + frame_params->refresh_bwd_ref_frame = 1; + frame_params->refresh_alt2_ref_frame = 0; } else { - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 1; + frame_params->refresh_bwd_ref_frame = 0; + frame_params->refresh_alt2_ref_frame = 1; } - cpi->refresh_alt_ref_frame = 0; + frame_params->refresh_alt_ref_frame = 0; break; default: assert(0); break; } + + if (cpi->ext_refresh_frame_flags_pending && + (cpi->oxcf.pass == 0 || cpi->oxcf.pass == 2)) { + frame_params->refresh_last_frame = cpi->ext_refresh_last_frame; + frame_params->refresh_golden_frame = cpi->ext_refresh_golden_frame; + frame_params->refresh_alt_ref_frame = cpi->ext_refresh_alt_ref_frame; + frame_params->refresh_bwd_ref_frame = cpi->ext_refresh_bwd_ref_frame; + frame_params->refresh_alt2_ref_frame = cpi->ext_refresh_alt2_ref_frame; + } + + if (force_refresh_all) { + frame_params->refresh_last_frame = 1; + frame_params->refresh_golden_frame = 1; + frame_params->refresh_bwd_ref_frame = 1; + frame_params->refresh_alt2_ref_frame = 1; + frame_params->refresh_alt_ref_frame = 1; + } } static void set_additional_frame_flags(const AV1_COMMON *const cm, @@ -158,9 +141,7 @@ static void set_additional_frame_flags(const AV1_COMMON *const cm, } static INLINE void update_keyframe_counters(AV1_COMP *cpi) { - // TODO(zoeliu): To investigate whether we should treat BWDREF_FRAME - // differently here for rc->avg_frame_bandwidth. - if (cpi->common.show_frame || cpi->rc.is_bwd_ref_frame) { + if (cpi->common.show_frame) { if (!cpi->common.show_existing_frame || cpi->rc.is_src_frame_alt_ref || cpi->common.current_frame.frame_type == KEY_FRAME) { // If this is a show_existing_frame with a source other than altref, @@ -207,47 +188,27 @@ static void update_rc_counts(AV1_COMP *cpi) { if (cpi->oxcf.pass == 2) update_twopass_gf_group_index(cpi); } -static void check_show_existing_frame(AV1_COMP *cpi) { +static void check_show_existing_frame(AV1_COMP *const cpi, + EncodeFrameParams *const frame_params) { const GF_GROUP *const gf_group = &cpi->twopass.gf_group; AV1_COMMON *const cm = &cpi->common; - const FRAME_UPDATE_TYPE next_frame_update_type = + const FRAME_UPDATE_TYPE frame_update_type = gf_group->update_type[gf_group->index]; - const int which_arf = (cpi->new_bwdref_update_rule == 1) - ? gf_group->arf_update_idx[gf_group->index] > 0 - : gf_group->arf_update_idx[gf_group->index]; + const int which_arf = (gf_group->arf_update_idx[gf_group->index] > 0); if (cm->show_existing_frame == 1) { - cm->show_existing_frame = 0; - } else if (cpi->rc.is_last_bipred_frame) { - // NOTE: When new structure is used, every bwdref will have one overlay - // frame. Therefore, there is no need to find out which frame to - // show in advance. - if (cpi->new_bwdref_update_rule == 0) { - // NOTE: If the current frame is a last bi-predictive frame, it is - // needed next to show the BWDREF_FRAME, which is pointed by - // the last_fb_idxes[0] after reference frame buffer update - cpi->rc.is_last_bipred_frame = 0; - cm->show_existing_frame = 1; - cpi->existing_fb_idx_to_show = cm->remapped_ref_idx[0]; - } + frame_params->show_existing_frame = 0; } else if (cpi->is_arf_filter_off[which_arf] && - (next_frame_update_type == OVERLAY_UPDATE || - next_frame_update_type == INTNL_OVERLAY_UPDATE)) { - const int bwdref_to_show = - (cpi->new_bwdref_update_rule == 1) ? BWDREF_FRAME : ALTREF2_FRAME; + (frame_update_type == OVERLAY_UPDATE || + frame_update_type == INTNL_OVERLAY_UPDATE)) { // Other parameters related to OVERLAY_UPDATE will be taken care of - // in av1_rc_get_second_pass_params(cpi) - cm->show_existing_frame = 1; - cpi->rc.is_src_frame_alt_ref = 1; - cpi->existing_fb_idx_to_show = - (next_frame_update_type == OVERLAY_UPDATE) + // in av1_get_second_pass_params(cpi) + frame_params->show_existing_frame = 1; + frame_params->existing_fb_idx_to_show = + (frame_update_type == OVERLAY_UPDATE) ? get_ref_frame_map_idx(cm, ALTREF_FRAME) - : get_ref_frame_map_idx(cm, bwdref_to_show); - if (cpi->new_bwdref_update_rule == 0) { - cpi->is_arf_filter_off[which_arf] = 0; - } + : get_ref_frame_map_idx(cm, BWDREF_FRAME); } - cpi->rc.is_src_frame_ext_arf = 0; } static void set_ext_overrides(AV1_COMP *const cpi, @@ -267,14 +228,6 @@ static void set_ext_overrides(AV1_COMP *const cpi, cm->refresh_frame_context = cpi->ext_refresh_frame_context; cpi->ext_refresh_frame_context_pending = 0; } - if (cpi->ext_refresh_frame_flags_pending) { - cpi->refresh_last_frame = cpi->ext_refresh_last_frame; - cpi->refresh_golden_frame = cpi->ext_refresh_golden_frame; - cpi->refresh_alt_ref_frame = cpi->ext_refresh_alt_ref_frame; - cpi->refresh_bwd_ref_frame = cpi->ext_refresh_bwd_ref_frame; - cpi->refresh_alt2_ref_frame = cpi->ext_refresh_alt2_ref_frame; - cpi->ext_refresh_frame_flags_pending = 0; - } cm->allow_ref_frame_mvs = cpi->ext_use_ref_frame_mvs; frame_params->error_resilient_mode = cpi->ext_use_error_resilient; @@ -375,14 +328,14 @@ static int get_current_frame_ref_type( cpi->ext_use_primary_ref_none) return REGULAR_FRAME; else if (gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) - return EXT_ARF_FRAME; - else if (cpi->refresh_alt_ref_frame) + return INTERNAL_ARF_FRAME; + else if (frame_params->refresh_alt_ref_frame) return ARF_FRAME; else if (cpi->rc.is_src_frame_alt_ref) return OVERLAY_FRAME; - else if (cpi->refresh_golden_frame) + else if (frame_params->refresh_golden_frame) return GLD_FRAME; - else if (cpi->refresh_bwd_ref_frame) + else if (frame_params->refresh_bwd_ref_frame) return BRF_FRAME; else return REGULAR_FRAME; @@ -431,9 +384,6 @@ static void update_fb_of_context_type( if (!encode_show_existing_frame(cm)) { // Refresh fb_of_context_type[]: see encoder.h for explanation - // Note that we want the value of refresh_frame_flags for the frame that - // just happened. If we call get_refresh_frame_flags now we will get a - // different answer, because update_reference_frames() has happened. if (cm->current_frame.frame_type == KEY_FRAME) { // All ref frames are refreshed, pick one that will live long enough fb_of_context_type[REGULAR_FRAME] = 0; @@ -452,18 +402,16 @@ static void update_fb_of_context_type( } } -static int get_order_offset(const AV1_COMP *const cpi, +static int get_order_offset(const GF_GROUP *const gf_group, const EncodeFrameParams *const frame_params) { // shown frame by definition has order offset 0 // show_existing_frame ignores order_offset and simply takes the order_hint // from the reference frame being shown. - if (frame_params->show_frame || cpi->common.show_existing_frame) return 0; + if (frame_params->show_frame || frame_params->show_existing_frame) return 0; - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; const int arf_offset = AOMMIN((MAX_GF_INTERVAL - 1), gf_group->arf_src_offset[gf_group->index]); - const int brf_offset = gf_group->brf_src_offset[gf_group->index]; - return AOMMIN((MAX_GF_INTERVAL - 1), arf_offset + brf_offset); + return AOMMIN((MAX_GF_INTERVAL - 1), arf_offset); } static void adjust_frame_rate(AV1_COMP *cpi, @@ -508,92 +456,35 @@ static void adjust_frame_rate(AV1_COMP *cpi, cpi->last_end_time_stamp_seen = source->ts_end; } -static void check_src_altref(AV1_COMP *cpi, - const struct lookahead_entry *source) { - RATE_CONTROL *const rc = &cpi->rc; - - // If pass == 2, the parameters set here will be reset in - // av1_rc_get_second_pass_params() - - if (cpi->oxcf.pass == 2) { - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - rc->is_src_frame_alt_ref = - (gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE) || - (gf_group->update_type[gf_group->index] == OVERLAY_UPDATE); - rc->is_src_frame_ext_arf = - gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE; - } else { - rc->is_src_frame_alt_ref = - cpi->alt_ref_source && (source == cpi->alt_ref_source); - } - - if (rc->is_src_frame_alt_ref) { - // Current frame is an ARF overlay frame. - cpi->alt_ref_source = NULL; - - if (rc->is_src_frame_ext_arf && !cpi->common.show_existing_frame) { - // For INTNL_OVERLAY, when show_existing_frame == 0, they do need to - // refresh the LAST_FRAME, i.e. LAST3 gets retired, LAST2 becomes LAST3, - // LAST becomes LAST2, and INTNL_OVERLAY becomes LAST. - cpi->refresh_last_frame = 1; - } else { - // Don't refresh the last buffer for an ARF overlay frame. It will - // become the GF so preserve last as an alternative prediction option. - cpi->refresh_last_frame = 0; - } - } -} - -// Returns 0 if this is not an alt ref else the offset of the source frame -// used as the arf midpoint. +// If this is an alt-ref, returns the offset of the source frame used +// as the arf midpoint. Otherwise, returns 0. static int get_arf_src_index(AV1_COMP *cpi) { RATE_CONTROL *const rc = &cpi->rc; int arf_src_index = 0; - if (is_altref_enabled(cpi)) { - if (cpi->oxcf.pass == 2) { - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - if (gf_group->update_type[gf_group->index] == ARF_UPDATE) { - arf_src_index = gf_group->arf_src_offset[gf_group->index]; - } - } else if (rc->source_alt_ref_pending) { - arf_src_index = rc->frames_till_gf_update_due; + if (cpi->oxcf.pass == 2) { + const GF_GROUP *const gf_group = &cpi->twopass.gf_group; + if (gf_group->update_type[gf_group->index] == ARF_UPDATE) { + assert(is_altref_enabled(cpi)); + arf_src_index = gf_group->arf_src_offset[gf_group->index]; } + } else if (rc->source_alt_ref_pending) { + arf_src_index = rc->frames_till_gf_update_due; } return arf_src_index; } -static int get_brf_src_index(AV1_COMP *cpi) { - int brf_src_index = 0; - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - - // TODO(zoeliu): We need to add the check on the -bwd_ref command line setup - // flag. - if (gf_group->bidir_pred_enabled[gf_group->index]) { - if (cpi->oxcf.pass == 2) { - if (gf_group->update_type[gf_group->index] == BRF_UPDATE) - brf_src_index = gf_group->brf_src_offset[gf_group->index]; - } else { - // TODO(zoeliu): To re-visit the setup for this scenario - brf_src_index = cpi->rc.bipred_group_interval - 1; +// If this is an internal alt-ref, returns the offset of the source frame used +// as the internal arf midpoint. Otherwise, returns 0. +static int get_internal_arf_src_index(AV1_COMP *cpi) { + int internal_arf_src_index = 0; + if (cpi->oxcf.pass == 2) { + const GF_GROUP *const gf_group = &cpi->twopass.gf_group; + if (gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) { + assert(is_altref_enabled(cpi) && cpi->internal_altref_allowed); + internal_arf_src_index = gf_group->arf_src_offset[gf_group->index]; } } - - return brf_src_index; -} - -// Returns 0 if this is not an alt ref else the offset of the source frame -// used as the arf midpoint. -static int get_arf2_src_index(AV1_COMP *cpi) { - int arf2_src_index = 0; - if (is_altref_enabled(cpi) && cpi->num_extra_arfs) { - if (cpi->oxcf.pass == 2) { - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - if (gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) { - arf2_src_index = gf_group->arf_src_offset[gf_group->index]; - } - } - } - return arf2_src_index; + return internal_arf_src_index; } // Called if this frame is an ARF or ARF2. Also handles forward-keyframes @@ -633,12 +524,6 @@ static struct lookahead_entry *setup_arf_or_arf2( } } frame_params->show_frame = 0; - - if (oxcf->pass < 2) { - // In second pass, the buffer updates configure will be set - // in the function av1_rc_get_second_pass_params - av1_configure_buffer_updates(cpi, arf2 ? INTNL_ARF_UPDATE : ARF_UPDATE); - } } rc->source_alt_ref_pending = 0; return source; @@ -662,12 +547,13 @@ static int is_forced_keyframe_pending(struct lookahead_ctx *lookahead, return 0; // Never reached } -// Check if we should encode an ARF, ARF2 or BRF. If not, try a LAST +// Check if we should encode an ARF or internal ARF. If not, try a LAST // Do some setup associated with the chosen source +// temporal_filtered, flush, and frame_update_type are outputs. // Return the frame source, or NULL if we couldn't find one struct lookahead_entry *choose_frame_source( AV1_COMP *const cpi, int *const temporal_filtered, int *const flush, - struct lookahead_entry **last_source, + struct lookahead_entry **last_source, FRAME_UPDATE_TYPE *frame_update_type, EncodeFrameParams *const frame_params) { AV1_COMMON *const cm = &cpi->common; struct lookahead_entry *source = NULL; @@ -684,10 +570,11 @@ struct lookahead_entry *choose_frame_source( if (arf_src_index) { source = setup_arf_or_arf2(cpi, arf_src_index, 0, temporal_filtered, frame_params); + *frame_update_type = ARF_UPDATE; } - // Should we encode an arf2 frame (mutually exclusive to ARF) - arf_src_index = get_arf2_src_index(cpi); + // Should we encode an internal Alt-ref frame (mutually exclusive to ARF) + arf_src_index = get_internal_arf_src_index(cpi); if (arf_src_index && is_forced_keyframe_pending(cpi->lookahead, arf_src_index)) { arf_src_index = 0; @@ -697,22 +584,7 @@ struct lookahead_entry *choose_frame_source( if (arf_src_index) { source = setup_arf_or_arf2(cpi, arf_src_index, 1, temporal_filtered, frame_params); - } - - cpi->rc.is_bwd_ref_frame = 0; - int brf_src_index = get_brf_src_index(cpi); - if (brf_src_index) { - assert(brf_src_index <= cpi->rc.frames_to_key); - if ((source = av1_lookahead_peek(cpi->lookahead, brf_src_index)) != NULL) { - cm->showable_frame = 1; - frame_params->show_frame = 0; - - if (cpi->oxcf.pass < 2) { - // In second pass, the buffer updates configure will be set - // in the function av1_rc_get_second_pass_params - av1_configure_buffer_updates(cpi, BRF_UPDATE); - } - } + *frame_update_type = INTNL_ARF_UPDATE; } if (!source) { @@ -722,17 +594,356 @@ struct lookahead_entry *choose_frame_source( } // Read in the source frame. source = av1_lookahead_pop(cpi->lookahead, *flush); + if (source == NULL) return NULL; + *frame_update_type = LF_UPDATE; // Default update type + frame_params->show_frame = 1; - if (source != NULL) { - frame_params->show_frame = 1; - - // Check to see if the frame should be encoded as an arf overlay. - check_src_altref(cpi, source); + // Check to see if the frame should be encoded as an arf overlay. + if (cpi->alt_ref_source == source) { + *frame_update_type = OVERLAY_UPDATE; + cpi->alt_ref_source = NULL; } } return source; } +// Don't allow a show_existing_frame to coincide with an error resilient or +// S-Frame. An exception can be made in the case of a keyframe, since it does +// not depend on any previous frames. +static int allow_show_existing(const AV1_COMP *const cpi, + unsigned int frame_flags) { + if (cpi->common.current_frame.frame_number == 0) return 0; + + const struct lookahead_entry *lookahead_src = + av1_lookahead_peek(cpi->lookahead, 0); + if (lookahead_src == NULL) return 1; + + const int is_error_resilient = + cpi->oxcf.error_resilient_mode || + (lookahead_src->flags & AOM_EFLAG_ERROR_RESILIENT); + const int is_s_frame = + cpi->oxcf.s_frame_mode || (lookahead_src->flags & AOM_EFLAG_SET_S_FRAME); + const int is_key_frame = + (cpi->rc.frames_to_key == 0) || (frame_flags & FRAMEFLAGS_KEY); + return !(is_error_resilient || is_s_frame) || is_key_frame; +} + +// Update frame_flags to tell the encoder's caller what sort of frame was +// encoded. +static void update_frame_flags(AV1_COMP *cpi, unsigned int *frame_flags) { + if (encode_show_existing_frame(&cpi->common)) { + *frame_flags &= ~FRAMEFLAGS_GOLDEN; + *frame_flags &= ~FRAMEFLAGS_BWDREF; + *frame_flags &= ~FRAMEFLAGS_ALTREF; + *frame_flags &= ~FRAMEFLAGS_KEY; + return; + } + + if (cpi->refresh_golden_frame == 1) { + *frame_flags |= FRAMEFLAGS_GOLDEN; + } else { + *frame_flags &= ~FRAMEFLAGS_GOLDEN; + } + + if (cpi->refresh_alt_ref_frame == 1) { + *frame_flags |= FRAMEFLAGS_ALTREF; + } else { + *frame_flags &= ~FRAMEFLAGS_ALTREF; + } + + if (cpi->refresh_bwd_ref_frame == 1) { + *frame_flags |= FRAMEFLAGS_BWDREF; + } else { + *frame_flags &= ~FRAMEFLAGS_BWDREF; + } + + if (cpi->common.current_frame.frame_type == KEY_FRAME) { + *frame_flags |= FRAMEFLAGS_KEY; + } else { + *frame_flags &= ~FRAMEFLAGS_KEY; + } +} + +#define DUMP_REF_FRAME_IMAGES 0 + +#if DUMP_REF_FRAME_IMAGES == 1 +static int dump_one_image(AV1_COMMON *cm, + const YV12_BUFFER_CONFIG *const ref_buf, + char *file_name) { + int h; + FILE *f_ref = NULL; + + if (ref_buf == NULL) { + printf("Frame data buffer is NULL.\n"); + return AOM_CODEC_MEM_ERROR; + } + + if ((f_ref = fopen(file_name, "wb")) == NULL) { + printf("Unable to open file %s to write.\n", file_name); + return AOM_CODEC_MEM_ERROR; + } + + // --- Y --- + for (h = 0; h < cm->height; ++h) { + fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref); + } + // --- U --- + for (h = 0; h < (cm->height >> 1); ++h) { + fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), + f_ref); + } + // --- V --- + for (h = 0; h < (cm->height >> 1); ++h) { + fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), + f_ref); + } + + fclose(f_ref); + + return AOM_CODEC_OK; +} + +static void dump_ref_frame_images(AV1_COMP *cpi) { + AV1_COMMON *const cm = &cpi->common; + MV_REFERENCE_FRAME ref_frame; + + for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + char file_name[256] = ""; + snprintf(file_name, sizeof(file_name), "/tmp/enc_F%d_ref_%d.yuv", + cm->current_frame.frame_number, ref_frame); + dump_one_image(cm, get_ref_frame_yv12_buf(cpi, ref_frame), file_name); + } +} +#endif // DUMP_REF_FRAME_IMAGES == 1 + +// Assign new_ref in the new mapping to point at the reference buffer pointed at +// by old_ref in the old_map. The new mapping is stored in *new_map, while the +// old map comes from cm->remapped_ref_idx[]. +static void assign_new_map(AV1_COMMON *const cm, int *new_map, int new_ref, + int old_ref) { + new_map[new_ref - LAST_FRAME] = cm->remapped_ref_idx[old_ref - LAST_FRAME]; +} + +// Generate a new reference frame mapping. This function updates +// cm->remapped_ref_idx[] depending on the frame_update_type of this frame. +// This determines which references (e.g. LAST_FRAME, ALTREF_FRAME) point at the +// 8 underlying buffers and, together with get_refresh_frame_flags(), implements +// our reference frame management strategy. +static void update_ref_frame_map(AV1_COMP *cpi, + FRAME_UPDATE_TYPE frame_update_type) { + AV1_COMMON *const cm = &cpi->common; + + // If check_frame_refs_short_signaling() decided to set + // frame_refs_short_signaling=1 then we update remapped_ref_idx[] here. Every + // reference will still map to the same RefCntBuffer (through ref_frame_map[]) + // after this, but that does not necessarily mean that remapped_ref_idx[] is + // unchanged. + if (cm->current_frame.frame_refs_short_signaling) { + const int lst_map_idx = get_ref_frame_map_idx(cm, LAST_FRAME); + const int gld_map_idx = get_ref_frame_map_idx(cm, GOLDEN_FRAME); + av1_set_frame_refs(cm, cm->remapped_ref_idx, lst_map_idx, gld_map_idx); + } + + // For shown keyframes and S-frames all buffers are refreshed, but we don't + // change any of the mapping. + if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) || + frame_is_sframe(cm)) { + return; + } + + // Initialize the new reference map as a copy of the old one. + int new_map[REF_FRAMES]; + memcpy(new_map, cm->remapped_ref_idx, sizeof(new_map)); + + // The reference management strategy is currently as follows. See + // gop_structure.c for more details of the structure and DOI + // 10.1109/DCC.2018.00045 for a higher-level explanation + // + // * ALTREF_FRAME and GOLDEN_FRAME are kept separate from the other + // references. When we code an ALTREF it refreshes the ALTREF buffer. When + // we code an OVERLAY the old GOLDEN becomes the new ALTREF and the old + // ALTREF (possibly refreshed by the OVERLAY) becomes the new GOLDEN. + // * LAST_FRAME, LAST2_FRAME, and LAST3_FRAME work like a FIFO. When we code + // a frame which does a last-frame update we pick a buffer to refresh and + // then point the LAST_FRAME reference at it. The old LAST_FRAME becomes + // LAST2_FRAME and the old LAST2_FRAME becomes LAST3_FRAME. The old + // LAST3_FRAME is re-used somewhere else. + // * BWDREF, ALTREF2, and EXTREF act like a stack structure, so we can + // "push" and "pop" internal alt-ref frames through the three references. + // * When we code a BRF or internal-ARF (they work the same in this + // structure) we push it onto the bwdref stack. Because we have a finite + // number of buffers, we actually refresh EXTREF, the bottom of the stack, + // and rotate the three references to make EXTREF the top. + // * When we code an INTNL_OVERLAY we refresh BWDREF, then pop it off of the + // bwdref stack and push it into the last-frame FIFO. The old LAST3 + // buffer gets pushed out of the last-frame FIFO and becomes the new + // EXTREF, bottom of the bwdref stack. + // * LAST_BIPRED just acts like a LAST_FRAME. The BWDREF will have an + // INTNL_OVERLAY and so can do its own ref map update. + // + // Note that this function runs *after* a frame has been coded, so it does not + // affect reference assignment of the current frame, it only affects future + // frames. This is why we refresh buffers using the old reference map before + // remapping them. + // + // show_existing_frames don't refresh any buffers or send the reference map to + // the decoder, but we can still update our reference map if we want to: the + // decoder will update its map next time we code a non-show-existing frame. + + if (frame_update_type == OVERLAY_UPDATE) { + // We want the old golden-frame to become our new ARF so swap the + // references. If cpi->preserve_arf_as_gld == 0 then we will refresh the + // old ARF before it becomes our new GF + assign_new_map(cm, new_map, ALTREF_FRAME, GOLDEN_FRAME); + assign_new_map(cm, new_map, GOLDEN_FRAME, ALTREF_FRAME); + } else if (frame_update_type == INTNL_OVERLAY_UPDATE && + encode_show_existing_frame(cm)) { + // Note that because encode_show_existing_frame(cm) we don't refresh any + // buffers. + // Pop BWDREF (shown as current frame) from the bwdref stack and make it + // the new LAST_FRAME. + assign_new_map(cm, new_map, LAST_FRAME, BWDREF_FRAME); + + // Progress the last-frame FIFO and the bwdref stack + assign_new_map(cm, new_map, LAST2_FRAME, LAST_FRAME); + assign_new_map(cm, new_map, LAST3_FRAME, LAST2_FRAME); + assign_new_map(cm, new_map, BWDREF_FRAME, ALTREF2_FRAME); + assign_new_map(cm, new_map, ALTREF2_FRAME, EXTREF_FRAME); + assign_new_map(cm, new_map, EXTREF_FRAME, LAST3_FRAME); + } else if (frame_update_type == INTNL_ARF_UPDATE && + !cm->show_existing_frame) { + // We want to push the current frame onto the bwdref stack. We refresh + // EXTREF (the old bottom of the stack) and rotate the references so it + // becomes BWDREF, the top of the stack. + assign_new_map(cm, new_map, BWDREF_FRAME, EXTREF_FRAME); + assign_new_map(cm, new_map, ALTREF2_FRAME, BWDREF_FRAME); + assign_new_map(cm, new_map, EXTREF_FRAME, ALTREF2_FRAME); + } + + if ((frame_update_type == LF_UPDATE || frame_update_type == GF_UPDATE || + frame_update_type == INTNL_OVERLAY_UPDATE) && + !encode_show_existing_frame(cm) && + (!cm->show_existing_frame || frame_update_type == INTNL_OVERLAY_UPDATE)) { + // A standard last-frame: we refresh the LAST3_FRAME buffer and then push it + // into the last-frame FIFO. + assign_new_map(cm, new_map, LAST3_FRAME, LAST2_FRAME); + assign_new_map(cm, new_map, LAST2_FRAME, LAST_FRAME); + assign_new_map(cm, new_map, LAST_FRAME, LAST3_FRAME); + } + + memcpy(cm->remapped_ref_idx, new_map, sizeof(new_map)); + +#if DUMP_REF_FRAME_IMAGES == 1 + // Dump out all reference frame images. + dump_ref_frame_images(cpi); +#endif // DUMP_REF_FRAME_IMAGES +} + +static int get_refresh_frame_flags(const AV1_COMP *const cpi, + const EncodeFrameParams *const frame_params, + FRAME_UPDATE_TYPE frame_update_type) { + const AV1_COMMON *const cm = &cpi->common; + + // Switch frames and shown key-frames overwrite all reference slots + if ((frame_params->frame_type == KEY_FRAME && frame_params->show_frame) || + frame_params->frame_type == S_FRAME) + return 0xFF; + + // show_existing_frames don't actually send refresh_frame_flags so set the + // flags to 0 to keep things consistent. + if (frame_params->show_existing_frame && + (!frame_params->error_resilient_mode || + frame_params->frame_type == KEY_FRAME)) { + return 0; + } + + int refresh_mask = 0; + + if (cpi->ext_refresh_frame_flags_pending) { + // Unfortunately the encoder interface reflects the old refresh_*_frame + // flags so we have to replicate the old refresh_frame_flags logic here in + // order to preserve the behaviour of the flag overrides. + refresh_mask |= cpi->ext_refresh_last_frame + << get_ref_frame_map_idx(cm, LAST3_FRAME); + refresh_mask |= cpi->ext_refresh_bwd_ref_frame + << get_ref_frame_map_idx(cm, EXTREF_FRAME); + refresh_mask |= cpi->ext_refresh_alt2_ref_frame + << get_ref_frame_map_idx(cm, ALTREF2_FRAME); + if (frame_update_type == OVERLAY_UPDATE) { + if (!cpi->preserve_arf_as_gld) { + refresh_mask |= cpi->ext_refresh_golden_frame + << get_ref_frame_map_idx(cm, ALTREF_FRAME); + } + } else { + refresh_mask |= cpi->ext_refresh_golden_frame + << get_ref_frame_map_idx(cm, GOLDEN_FRAME); + refresh_mask |= cpi->ext_refresh_alt_ref_frame + << get_ref_frame_map_idx(cm, ALTREF_FRAME); + } + return refresh_mask; + } + + // See update_ref_frame_map() for a thorough description of the reference + // buffer management strategy currently in use. This function just decides + // which buffers should be refreshed. + + switch (frame_update_type) { + case KF_UPDATE: + // Note that a real shown key-frame or S-frame refreshes every buffer, + // handled in a special case above. This case is for frames which aren't + // really a shown key-frame or S-frame but want to refresh all the + // important buffers. + refresh_mask |= 1 << get_ref_frame_map_idx(cm, LAST3_FRAME); + refresh_mask |= 1 << get_ref_frame_map_idx(cm, EXTREF_FRAME); + refresh_mask |= 1 << get_ref_frame_map_idx(cm, ALTREF2_FRAME); + refresh_mask |= 1 << get_ref_frame_map_idx(cm, GOLDEN_FRAME); + refresh_mask |= 1 << get_ref_frame_map_idx(cm, ALTREF_FRAME); + break; + case LF_UPDATE: + // Refresh LAST3, which becomes the new LAST while LAST becomes LAST2 + // and LAST2 becomes the new LAST3 (like a FIFO but circular) + refresh_mask |= 1 << get_ref_frame_map_idx(cm, LAST3_FRAME); + break; + case GF_UPDATE: + // In addition to refreshing the GF buffer, we refresh LAST3 and push it + // into the last-frame FIFO. + refresh_mask |= 1 << get_ref_frame_map_idx(cm, LAST3_FRAME); + refresh_mask |= 1 << get_ref_frame_map_idx(cm, GOLDEN_FRAME); + break; + case OVERLAY_UPDATE: + if (!cpi->preserve_arf_as_gld) { + // The result of our OVERLAY should become the GOLDEN_FRAME but we'd + // like to keep the old GOLDEN as our new ALTREF. So we refresh the + // ALTREF and swap around the ALTREF and GOLDEN references. + refresh_mask |= 1 << get_ref_frame_map_idx(cm, ALTREF_FRAME); + } + break; + case ARF_UPDATE: + refresh_mask |= 1 << get_ref_frame_map_idx(cm, ALTREF_FRAME); + break; + case INTNL_OVERLAY_UPDATE: + // INTNL_OVERLAY may be a show_existing_frame in which case we don't + // refresh anything and the BWDREF or ALTREF2 being shown becomes the new + // LAST_FRAME. But, if it's not a show_existing_frame, then we update as + // though it's a normal LF_UPDATE: we refresh LAST3 and + // update_ref_frame_map() makes that the new LAST_FRAME. + refresh_mask |= 1 << get_ref_frame_map_idx(cm, LAST3_FRAME); + break; + case INTNL_ARF_UPDATE: + if (cpi->oxcf.pass == 2) { + // Push the new ARF2 onto the bwdref stack. We refresh EXTREF which is + // at the bottom of the stack then move it to the top. + refresh_mask |= 1 << get_ref_frame_map_idx(cm, EXTREF_FRAME); + } else { + // ARF2 just gets stored in the ARF2 slot, no reference map change. + refresh_mask |= 1 << get_ref_frame_map_idx(cm, ALTREF2_FRAME); + } + break; + default: assert(0); break; + } + return refresh_mask; +} + int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, uint8_t *const dest, unsigned int *frame_flags, int64_t *const time_stamp, int64_t *const time_end, @@ -747,14 +958,29 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, memset(&frame_params, 0, sizeof(frame_params)); memset(&frame_results, 0, sizeof(frame_results)); + if (oxcf->pass == 0 || oxcf->pass == 2) { + check_show_existing_frame(cpi, &frame_params); + frame_params.show_existing_frame &= allow_show_existing(cpi, *frame_flags); + } else { + frame_params.show_existing_frame = 0; + } + int temporal_filtered = 0; struct lookahead_entry *source = NULL; struct lookahead_entry *last_source = NULL; - if (cm->show_existing_frame) { + FRAME_UPDATE_TYPE frame_update_type; + if (frame_params.show_existing_frame) { source = av1_lookahead_pop(cpi->lookahead, flush); + frame_update_type = LF_UPDATE; } else { source = choose_frame_source(cpi, &temporal_filtered, &flush, &last_source, - &frame_params); + &frame_update_type, &frame_params); + } + + // In pass 2 we get the frame_update_type from gf_group + if (oxcf->pass == 2) { + frame_update_type = + cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]; } if (source == NULL) { // If no source was found, we can't encode a frame. @@ -777,60 +1003,48 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, } av1_apply_encoding_flags(cpi, source->flags); - if (!cm->show_existing_frame) + if (!frame_params.show_existing_frame) *frame_flags = (source->flags & AOM_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0; - cpi->frame_flags = *frame_flags; - if (frame_params.show_frame || - (cm->show_existing_frame && cpi->rc.is_src_frame_alt_ref)) { + const int is_overlay = frame_params.show_existing_frame && + (frame_update_type == OVERLAY_UPDATE || + frame_update_type == INTNL_OVERLAY_UPDATE); + if (frame_params.show_frame || is_overlay) { // Shown frames and arf-overlay frames need frame-rate considering adjust_frame_rate(cpi, source); } - if (cm->show_existing_frame) { + if (frame_params.show_existing_frame) { // show_existing_frame implies this frame is shown! frame_params.show_frame = 1; } else { - // Retain the RF_LEVEL for the current newly coded frame. - cm->cur_frame->frame_rf_level = - cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index]; - if (cpi->film_grain_table) { - cm->seq_params.film_grain_params_present = aom_film_grain_table_lookup( + cm->cur_frame->film_grain_params_present = aom_film_grain_table_lookup( cpi->film_grain_table, *time_stamp, *time_end, 0 /* =erase */, &cm->film_grain_params); + } else { + cm->cur_frame->film_grain_params_present = + cm->seq_params.film_grain_params_present; } - cm->cur_frame->film_grain_params_present = - cm->seq_params.film_grain_params_present; - // only one operating point supported now const int64_t pts64 = ticks_to_timebase_units(timebase, *time_stamp); if (pts64 < 0 || pts64 > UINT32_MAX) return AOM_CODEC_ERROR; cpi->common.frame_presentation_time = (uint32_t)pts64; } - if (oxcf->pass == 2 && - (!cm->show_existing_frame || cpi->rc.is_src_frame_alt_ref)) { + if (oxcf->pass == 2 && (!frame_params.show_existing_frame || is_overlay)) { // GF_GROUP needs updating for arf overlays as well as non-show-existing - av1_rc_get_second_pass_params(cpi, &frame_params); + av1_get_second_pass_params(cpi, &frame_params, *frame_flags); + frame_update_type = + cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]; } - if (cm->show_existing_frame && frame_params.frame_type != KEY_FRAME) { + + if (frame_params.show_existing_frame && + frame_params.frame_type != KEY_FRAME) { // Force show-existing frames to be INTER, except forward keyframes frame_params.frame_type = INTER_FRAME; } - if (!cm->show_existing_frame) { - cm->using_qmatrix = cpi->oxcf.using_qm; - cm->min_qmlevel = cpi->oxcf.qm_minlevel; - cm->max_qmlevel = cpi->oxcf.qm_maxlevel; - if (cpi->twopass.gf_group.index == 1 && cpi->oxcf.enable_tpl_model) { - av1_set_frame_size(cpi, cm->width, cm->height); - av1_tpl_setup_stats(cpi, &frame_input); - } - } - - frame_params.frame_flags = frame_flags; - // TODO(david.turner@argondesign.com): Move all the encode strategy // (largely near av1_get_compressed_data) in here @@ -842,18 +1056,32 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, // parameter should be used with caution. frame_params.speed = oxcf->speed; + if (!frame_params.show_existing_frame) { + cm->using_qmatrix = cpi->oxcf.using_qm; + cm->min_qmlevel = cpi->oxcf.qm_minlevel; + cm->max_qmlevel = cpi->oxcf.qm_maxlevel; + if (cpi->twopass.gf_group.index == 1 && cpi->oxcf.enable_tpl_model) { + av1_configure_buffer_updates(cpi, &frame_params, frame_update_type, 0); + av1_set_frame_size(cpi, cm->width, cm->height); + av1_tpl_setup_stats(cpi, &frame_input); + } + } + // Work out some encoding parameters specific to the pass: if (oxcf->pass == 0) { if (cpi->oxcf.rc_mode == AOM_CBR) { - av1_rc_get_one_pass_cbr_params(cpi, &frame_params); + av1_rc_get_one_pass_cbr_params(cpi, &frame_update_type, &frame_params, + *frame_flags); } else { - av1_rc_get_one_pass_vbr_params(cpi, &frame_params); + av1_rc_get_one_pass_vbr_params(cpi, &frame_update_type, &frame_params, + *frame_flags); } } else if (oxcf->pass == 1) { - av1_setup_frame_size(cpi); cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&cpi->oxcf); - if (!cpi->refresh_alt_ref_frame && (cm->current_frame.frame_number == 0 || - (cpi->frame_flags & FRAMEFLAGS_KEY))) { + const int kf_requested = (cm->current_frame.frame_number == 0 || + (*frame_flags & FRAMEFLAGS_KEY)); + if (kf_requested && frame_update_type != OVERLAY_UPDATE && + frame_update_type != INTNL_OVERLAY_UPDATE) { frame_params.frame_type = KEY_FRAME; } else { frame_params.frame_type = INTER_FRAME; @@ -868,25 +1096,53 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, #endif } - if (oxcf->pass == 0 || oxcf->pass == 2) { - // Apply external override flags - set_ext_overrides(cpi, &frame_params); + if (oxcf->pass == 0 || oxcf->pass == 2) set_ext_overrides(cpi, &frame_params); + // Shown keyframes and S frames refresh all reference buffers + const int force_refresh_all = + ((frame_params.frame_type == KEY_FRAME && frame_params.show_frame) || + frame_params.frame_type == S_FRAME) && + !frame_params.show_existing_frame; + + av1_configure_buffer_updates(cpi, &frame_params, frame_update_type, + force_refresh_all); + + if (oxcf->pass == 0 || oxcf->pass == 2) { // Work out which reference frame slots may be used. frame_params.ref_frame_flags = get_ref_frame_flags(cpi); - } - if (oxcf->pass == 0 || oxcf->pass == 2) { frame_params.primary_ref_frame = choose_primary_ref_frame(cpi, &frame_params); - frame_params.order_offset = get_order_offset(cpi, &frame_params); + frame_params.order_offset = + get_order_offset(&cpi->twopass.gf_group, &frame_params); + + frame_params.refresh_frame_flags = + get_refresh_frame_flags(cpi, &frame_params, frame_update_type); } + // The way frame_params->remapped_ref_idx is setup is a placeholder. + // Currently, reference buffer assignment is done by update_ref_frame_map() + // which is called by high-level strategy AFTER encoding a frame. It modifies + // cm->remapped_ref_idx. If you want to use an alternative method to + // determine reference buffer assignment, just put your assignments into + // frame_params->remapped_ref_idx here and they will be used when encoding + // this frame. If frame_params->remapped_ref_idx is setup independently of + // cm->remapped_ref_idx then update_ref_frame_map() will have no effect. + memcpy(frame_params.remapped_ref_idx, cm->remapped_ref_idx, + REF_FRAMES * sizeof(*cm->remapped_ref_idx)); + if (av1_encode(cpi, dest, &frame_input, &frame_params, &frame_results) != AOM_CODEC_OK) { return AOM_CODEC_ERROR; } + if (oxcf->pass == 0 || oxcf->pass == 2) { + // First pass doesn't modify reference buffer assignment or produce frame + // flags + update_frame_flags(cpi, frame_flags); + update_ref_frame_map(cpi, frame_update_type); + } + if (oxcf->pass == 2) { #if TXCOEFF_COST_TIMER cm->cum_txcoeff_cost_timer += cm->txcoeff_cost_timer; @@ -901,9 +1157,8 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, if (oxcf->pass == 0 || oxcf->pass == 2) { update_fb_of_context_type(cpi, &frame_params, cpi->fb_of_context_type); - set_additional_frame_flags(cm, frame_params.frame_flags); + set_additional_frame_flags(cm, frame_flags); update_rc_counts(cpi); - check_show_existing_frame(cpi); // Is next frame a show_existing frame? } // Unpack frame_results: diff --git a/third_party/aom/av1/encoder/encode_strategy.h b/third_party/aom/av1/encoder/encode_strategy.h index 1671473b76..6830e44468 100644 --- a/third_party/aom/av1/encoder/encode_strategy.h +++ b/third_party/aom/av1/encoder/encode_strategy.h @@ -31,9 +31,13 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, int64_t *const time_stamp, int64_t *const time_end, const aom_rational_t *const timebase, int flush); -// Set individual buffer update flags based on frame reference type +// Set individual buffer update flags based on frame reference type. +// force_refresh_all is used when we have a KEY_FRAME or S_FRAME. It forces all +// refresh_*_frame flags to be set, because we refresh all buffers in this case. void av1_configure_buffer_updates(AV1_COMP *const cpi, - const FRAME_UPDATE_TYPE type); + EncodeFrameParams *const frame_params, + const FRAME_UPDATE_TYPE type, + int force_refresh_all); #ifdef __cplusplus } // extern "C" diff --git a/third_party/aom/av1/encoder/encodeframe.c b/third_party/aom/av1/encoder/encodeframe.c index ea8249300c..2952184cb5 100644 --- a/third_party/aom/av1/encoder/encodeframe.c +++ b/third_party/aom/av1/encoder/encodeframe.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -54,12 +55,14 @@ #include "av1/encoder/ethread.h" #include "av1/encoder/extend.h" #include "av1/encoder/ml.h" +#include "av1/encoder/partition_strategy.h" #include "av1/encoder/partition_model_weights.h" #include "av1/encoder/rd.h" #include "av1/encoder/rdopt.h" #include "av1/encoder/reconinter_enc.h" #include "av1/encoder/segmentation.h" #include "av1/encoder/tokenize.h" +#include "av1/encoder/var_based_part.h" static void encode_superblock(const AV1_COMP *const cpi, TileDataEnc *tile_data, ThreadData *td, TOKENEXTRA **t, RUN_TYPE dry_run, @@ -74,7 +77,7 @@ static int ml_predict_breakout(const AV1_COMP *const cpi, BLOCK_SIZE bsize, // purposes of activity masking. // Eventually this should be replaced by custom no-reference routines, // which will be faster. -static const uint8_t AV1_VAR_OFFS[MAX_SB_SIZE] = { +const uint8_t AV1_VAR_OFFS[MAX_SB_SIZE] = { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, @@ -139,24 +142,6 @@ static const uint16_t AV1_HIGH_VAR_OFFS_12[MAX_SB_SIZE] = { 128 * 16, 128 * 16 }; -#if CONFIG_FP_MB_STATS -static const uint8_t num_16x16_blocks_wide_lookup[BLOCK_SIZES_ALL] = { - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 1, 1, 1, 2, 2, 4 -}; -static const uint8_t num_16x16_blocks_high_lookup[BLOCK_SIZES_ALL] = { - 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 1, 1, 2, 1, 4, 2 -}; -#endif // CONFIG_FP_MB_STATS - -static const uint8_t ref_frame_flag_list[REF_FRAMES] = { 0, - AOM_LAST_FLAG, - AOM_LAST2_FLAG, - AOM_LAST3_FLAG, - AOM_GOLD_FLAG, - AOM_BWD_FLAG, - AOM_ALT2_FLAG, - AOM_ALT_FLAG }; - unsigned int av1_get_sby_perpixel_variance(const AV1_COMP *cpi, const struct buf_2d *ref, BLOCK_SIZE bs) { @@ -221,18 +206,6 @@ static BLOCK_SIZE get_rd_var_based_fixed_partition(AV1_COMP *cpi, MACROBLOCK *x, return BLOCK_8X8; } -// Lighter version of set_offsets that only sets the mode info -// pointers. -static void set_mode_info_offsets(const AV1_COMP *const cpi, - MACROBLOCK *const x, MACROBLOCKD *const xd, - int mi_row, int mi_col) { - const AV1_COMMON *const cm = &cpi->common; - const int idx_str = xd->mi_stride * mi_row + mi_col; - xd->mi = cm->mi_grid_visible + idx_str; - xd->mi[0] = cm->mi + idx_str; - x->mbmi_ext = cpi->mbmi_ext_base + (mi_row * cm->mi_cols + mi_col); -} - static void set_offsets_without_segment_id(const AV1_COMP *const cpi, const TileInfo *const tile, MACROBLOCK *const x, int mi_row, @@ -399,7 +372,6 @@ static void update_state(const AV1_COMP *const cpi, if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_update_segment(cpi, mi_addr, mi_row, mi_col, bsize, ctx->rate, ctx->dist, x->skip); - reset_tx_size(x, mi_addr, cm->tx_mode); } if (mi_addr->uv_mode == UV_CFL_PRED && !is_cfl_allowed(xd)) mi_addr->uv_mode = UV_DC_PRED; @@ -510,24 +482,32 @@ static int set_deltaq_rdmult(const AV1_COMP *const cpi, MACROBLOCKD *const xd) { cpi, cm->base_qindex + xd->delta_qindex + cm->y_dc_delta_q); } -static uint16_t edge_strength(const struct buf_2d *ref, const BLOCK_SIZE bsize, - const bool high_bd, const int bd) { +static EdgeInfo edge_info(const struct buf_2d *ref, const BLOCK_SIZE bsize, + const bool high_bd, const int bd) { const int width = block_size_wide[bsize]; const int height = block_size_high[bsize]; // Implementation requires width to be a multiple of 8. It also requires // height to be a multiple of 4, but this is always the case. assert(height % 4 == 0); if (width % 8 != 0) { - return 0; + EdgeInfo ei = { .magnitude = 0, .x = 0, .y = 0 }; + return ei; } return av1_edge_exists(ref->buf, ref->stride, width, height, high_bd, bd); } -static void rd_pick_sb_modes(AV1_COMP *const cpi, TileDataEnc *tile_data, - MACROBLOCK *const x, int mi_row, int mi_col, - RD_STATS *rd_cost, PARTITION_TYPE partition, - BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, - int64_t best_rd) { +static int use_pb_simple_motion_pred_sse(const AV1_COMP *const cpi) { + // TODO(debargha, yuec): Not in use, need to implement a speed feature + // utilizing this data point, and replace '0' by the corresponding speed + // feature flag. + return 0 && !frame_is_intra_only(&cpi->common); +} + +static void pick_sb_modes(AV1_COMP *const cpi, TileDataEnc *tile_data, + MACROBLOCK *const x, int mi_row, int mi_col, + RD_STATS *rd_cost, PARTITION_TYPE partition, + BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, + int64_t best_rd, int use_nonrd_pick_mode) { AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); TileInfo *const tile_info = &tile_data->tile_info; @@ -540,6 +520,10 @@ static void rd_pick_sb_modes(AV1_COMP *const cpi, TileDataEnc *tile_data, const DELTAQ_MODE deltaq_mode = cpi->oxcf.deltaq_mode; int i, orig_rdmult; +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, rd_pick_sb_modes_time); +#endif + if (best_rd < 0) { ctx->rdcost = INT64_MAX; ctx->skip = 0; @@ -607,13 +591,25 @@ static void rd_pick_sb_modes(AV1_COMP *const cpi, TileDataEnc *tile_data, x->source_variance = av1_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); } + if (use_pb_simple_motion_pred_sse(cpi)) { + const MV ref_mv_full = { .row = 0, .col = 0 }; + unsigned int var = 0; + av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, ref_mv_full, 0, + &x->simple_motion_pred_sse, &var); + } + // If the threshold for disabling wedge search is zero, it means the feature // should not be used. Use a value that will always succeed in the check. if (cpi->sf.disable_wedge_search_edge_thresh == 0) { x->edge_strength = UINT16_MAX; + x->edge_strength_x = UINT16_MAX; + x->edge_strength_y = UINT16_MAX; } else { - x->edge_strength = - edge_strength(&x->plane[0].src, bsize, is_cur_buf_hbd(xd), xd->bd); + EdgeInfo ei = + edge_info(&x->plane[0].src, bsize, is_cur_buf_hbd(xd), xd->bd); + x->edge_strength = ei.magnitude; + x->edge_strength_x = ei.x; + x->edge_strength_y = ei.y; } // Save rdmult before it might be changed, so it can be restored later. orig_rdmult = x->rdmult; @@ -641,22 +637,35 @@ static void rd_pick_sb_modes(AV1_COMP *const cpi, TileDataEnc *tile_data, // Find best coding mode & reconstruct the MB so it is available // as a predictor for MBs that follow in the SB if (frame_is_intra_only(cm)) { +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, av1_rd_pick_intra_mode_sb_time); +#endif av1_rd_pick_intra_mode_sb(cpi, x, mi_row, mi_col, rd_cost, bsize, ctx, best_rd); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, av1_rd_pick_intra_mode_sb_time); +#endif } else { +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, av1_rd_pick_inter_mode_sb_time); +#endif if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { av1_rd_pick_inter_mode_sb_seg_skip(cpi, tile_data, x, mi_row, mi_col, rd_cost, bsize, ctx, best_rd); -#if CONFIG_ONE_PASS_SVM - ctx->seg_feat = 1; -#endif } else { - av1_rd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost, - bsize, ctx, best_rd); -#if CONFIG_ONE_PASS_SVM - ctx->seg_feat = 0; -#endif + // TODO(kyslov): do the same for pick_intra_mode and + // pick_inter_mode_sb_seg_skip + if (use_nonrd_pick_mode) { + av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost, + bsize, ctx, best_rd); + } else { + av1_rd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost, + bsize, ctx, best_rd); + } } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, av1_rd_pick_inter_mode_sb_time); +#endif } // Examine the resulting rate and for AQ mode 2 make a segment choice. @@ -677,6 +686,10 @@ static void rd_pick_sb_modes(AV1_COMP *const cpi, TileDataEnc *tile_data, ctx->rate = rd_cost->rate; ctx->dist = rd_cost->dist; ctx->rdcost = rd_cost->rdcost; + +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, rd_pick_sb_modes_time); +#endif } static void update_inter_mode_stats(FRAME_CONTEXT *fc, FRAME_COUNTS *counts, @@ -1284,11 +1297,13 @@ static void update_stats(const AV1_COMMON *const cm, TileDataEnc *tile_data, assert(masked_compound_used); if (is_interinter_compound_used(COMPOUND_WEDGE, bsize)) { #if CONFIG_ENTROPY_STATS - ++counts->compound_type[bsize][mbmi->interinter_comp.type - 1]; + ++counts->compound_type[bsize][mbmi->interinter_comp.type - + COMPOUND_WEDGE]; #endif if (allow_update_cdf) { update_cdf(fc->compound_type_cdf[bsize], - mbmi->interinter_comp.type - 1, COMPOUND_TYPES - 1); + mbmi->interinter_comp.type - COMPOUND_WEDGE, + MASKED_COMPOUND_TYPES); } } } @@ -1619,25 +1634,6 @@ static void encode_sb(const AV1_COMP *const cpi, ThreadData *td, update_ext_partition_context(xd, mi_row, mi_col, subsize, bsize, partition); } -// Check to see if the given partition size is allowed for a specified number -// of mi block rows and columns remaining in the image. -// If not then return the largest allowed partition size -static BLOCK_SIZE find_partition_size(BLOCK_SIZE bsize, int rows_left, - int cols_left, int *bh, int *bw) { - if (rows_left <= 0 || cols_left <= 0) { - return AOMMIN(bsize, BLOCK_8X8); - } else { - for (; bsize > 0; bsize -= 3) { - *bh = mi_size_high[bsize]; - *bw = mi_size_wide[bsize]; - if ((*bh <= rows_left) && (*bw <= cols_left)) { - break; - } - } - } - return bsize; -} - static void set_partial_sb_partition(const AV1_COMMON *const cm, MB_MODE_INFO *mi, int bh_in, int bw_in, int mi_rows_remaining, @@ -1761,8 +1757,8 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, if (partition != PARTITION_NONE && !splits_below && mi_row + hbs < cm->mi_rows && mi_col + hbs < cm->mi_cols) { pc_tree->partitioning = PARTITION_NONE; - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &none_rdc, - PARTITION_NONE, bsize, ctx_none, INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &none_rdc, + PARTITION_NONE, bsize, ctx_none, INT64_MAX, 0); if (none_rdc.rate < INT_MAX) { none_rdc.rate += x->partition_cost[pl][PARTITION_NONE]; @@ -1774,29 +1770,16 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, pc_tree->partitioning = partition; } } - for (int b = 0; b < 2; ++b) { - pc_tree->horizontal[b].skip_ref_frame_mask = 0; - pc_tree->vertical[b].skip_ref_frame_mask = 0; - } - for (int b = 0; b < 3; ++b) { - pc_tree->horizontala[b].skip_ref_frame_mask = 0; - pc_tree->horizontalb[b].skip_ref_frame_mask = 0; - pc_tree->verticala[b].skip_ref_frame_mask = 0; - pc_tree->verticalb[b].skip_ref_frame_mask = 0; - } - for (int b = 0; b < 4; ++b) { - pc_tree->horizontal4[b].skip_ref_frame_mask = 0; - pc_tree->vertical4[b].skip_ref_frame_mask = 0; - } + switch (partition) { case PARTITION_NONE: - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, - PARTITION_NONE, bsize, ctx_none, INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, + PARTITION_NONE, bsize, ctx_none, INT64_MAX, 0); break; case PARTITION_HORZ: - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, - PARTITION_HORZ, subsize, &pc_tree->horizontal[0], - INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, + PARTITION_HORZ, subsize, &pc_tree->horizontal[0], INT64_MAX, + 0); if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && mi_row + hbs < cm->mi_rows) { RD_STATS tmp_rdc; @@ -1805,9 +1788,9 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, update_state(cpi, tile_data, td, ctx_h, mi_row, mi_col, subsize, 1); encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, mi_row, mi_col, subsize, NULL); - rd_pick_sb_modes(cpi, tile_data, x, mi_row + hbs, mi_col, &tmp_rdc, - PARTITION_HORZ, subsize, &pc_tree->horizontal[1], - INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row + hbs, mi_col, &tmp_rdc, + PARTITION_HORZ, subsize, &pc_tree->horizontal[1], + INT64_MAX, 0); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { av1_invalid_rd_stats(&last_part_rdc); break; @@ -1818,9 +1801,9 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, } break; case PARTITION_VERT: - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, - PARTITION_VERT, subsize, &pc_tree->vertical[0], - INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, + PARTITION_VERT, subsize, &pc_tree->vertical[0], INT64_MAX, + 0); if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && mi_col + hbs < cm->mi_cols) { RD_STATS tmp_rdc; @@ -1829,9 +1812,9 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, update_state(cpi, tile_data, td, ctx_v, mi_row, mi_col, subsize, 1); encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, mi_row, mi_col, subsize, NULL); - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + hbs, &tmp_rdc, - PARTITION_VERT, subsize, - &pc_tree->vertical[bsize > BLOCK_8X8], INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + hbs, &tmp_rdc, + PARTITION_VERT, subsize, + &pc_tree->vertical[bsize > BLOCK_8X8], INT64_MAX, 0); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { av1_invalid_rd_stats(&last_part_rdc); break; @@ -1905,9 +1888,9 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, save_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); pc_tree->split[i]->partitioning = PARTITION_NONE; - rd_pick_sb_modes(cpi, tile_data, x, mi_row + y_idx, mi_col + x_idx, - &tmp_rdc, PARTITION_SPLIT, split_subsize, - &pc_tree->split[i]->none, INT64_MAX); + pick_sb_modes(cpi, tile_data, x, mi_row + y_idx, mi_col + x_idx, &tmp_rdc, + PARTITION_SPLIT, split_subsize, &pc_tree->split[i]->none, + INT64_MAX, 0); restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { @@ -1968,67 +1951,170 @@ static void rd_use_partition(AV1_COMP *cpi, ThreadData *td, *dist = chosen_rdc.dist; } -/* clang-format off */ -static const BLOCK_SIZE min_partition_size[BLOCK_SIZES_ALL] = { - BLOCK_4X4, // 4x4 - BLOCK_4X4, BLOCK_4X4, BLOCK_4X4, // 4x8, 8x4, 8x8 - BLOCK_4X4, BLOCK_4X4, BLOCK_8X8, // 8x16, 16x8, 16x16 - BLOCK_8X8, BLOCK_8X8, BLOCK_16X16, // 16x32, 32x16, 32x32 - BLOCK_16X16, BLOCK_16X16, BLOCK_16X16, // 32x64, 64x32, 64x64 - BLOCK_16X16, BLOCK_16X16, BLOCK_16X16, // 64x128, 128x64, 128x128 - BLOCK_4X4, BLOCK_4X4, BLOCK_8X8, // 4x16, 16x4, 8x32 - BLOCK_8X8, BLOCK_16X16, BLOCK_16X16, // 32x8, 16x64, 64x16 -}; +// TODO(kyslov): now this is very similar to rd_use_partition (except that +// doesn't do extra search arounf suggested partitioning) +// consider passing a flag to select non-rd path (similar to +// encode_sb_row) +static void nonrd_use_partition(AV1_COMP *cpi, ThreadData *td, + TileDataEnc *tile_data, MB_MODE_INFO **mib, + TOKENEXTRA **tp, int mi_row, int mi_col, + BLOCK_SIZE bsize, int *rate, int64_t *dist, + int do_recon, PC_TREE *pc_tree) { + AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + TileInfo *const tile_info = &tile_data->tile_info; + MACROBLOCK *const x = &td->mb; + MACROBLOCKD *const xd = &x->e_mbd; + const int bs = mi_size_wide[bsize]; + const int hbs = bs / 2; + int i; + const int pl = (bsize >= BLOCK_8X8) + ? partition_plane_context(xd, mi_row, mi_col, bsize) + : 0; + const PARTITION_TYPE partition = + (bsize >= BLOCK_8X8) ? get_partition(cm, mi_row, mi_col, bsize) + : PARTITION_NONE; + const BLOCK_SIZE subsize = get_partition_subsize(bsize, partition); + RD_SEARCH_MACROBLOCK_CONTEXT x_ctx; + RD_STATS last_part_rdc; + PICK_MODE_CONTEXT *ctx_none = &pc_tree->none; -static const BLOCK_SIZE max_partition_size[BLOCK_SIZES_ALL] = { - BLOCK_8X8, // 4x4 - BLOCK_16X16, BLOCK_16X16, BLOCK_16X16, // 4x8, 8x4, 8x8 - BLOCK_32X32, BLOCK_32X32, BLOCK_32X32, // 8x16, 16x8, 16x16 - BLOCK_64X64, BLOCK_64X64, BLOCK_64X64, // 16x32, 32x16, 32x32 - BLOCK_LARGEST, BLOCK_LARGEST, BLOCK_LARGEST, // 32x64, 64x32, 64x64 - BLOCK_LARGEST, BLOCK_LARGEST, BLOCK_LARGEST, // 64x128, 128x64, 128x128 - BLOCK_16X16, BLOCK_16X16, BLOCK_32X32, // 4x16, 16x4, 8x32 - BLOCK_32X32, BLOCK_LARGEST, BLOCK_LARGEST, // 32x8, 16x64, 64x16 -}; + if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; -// Next square block size less or equal than current block size. -static const BLOCK_SIZE next_square_size[BLOCK_SIZES_ALL] = { - BLOCK_4X4, // 4x4 - BLOCK_4X4, BLOCK_4X4, BLOCK_8X8, // 4x8, 8x4, 8x8 - BLOCK_8X8, BLOCK_8X8, BLOCK_16X16, // 8x16, 16x8, 16x16 - BLOCK_16X16, BLOCK_16X16, BLOCK_32X32, // 16x32, 32x16, 32x32 - BLOCK_32X32, BLOCK_32X32, BLOCK_64X64, // 32x64, 64x32, 64x64 - BLOCK_64X64, BLOCK_64X64, BLOCK_128X128, // 64x128, 128x64, 128x128 - BLOCK_4X4, BLOCK_4X4, BLOCK_8X8, // 4x16, 16x4, 8x32 - BLOCK_8X8, BLOCK_16X16, BLOCK_16X16, // 32x8, 16x64, 64x16 -}; -/* clang-format on */ + assert(mi_size_wide[bsize] == mi_size_high[bsize]); -// Look at all the mode_info entries for blocks that are part of this -// partition and find the min and max values for sb_type. -// At the moment this is designed to work on a superblock but could be -// adjusted to use a size parameter. -// -// The min and max are assumed to have been initialized prior to calling this -// function so repeat calls can accumulate a min and max of more than one -// superblock. -static void get_sb_partition_size_range(const AV1_COMMON *const cm, - MACROBLOCKD *xd, MB_MODE_INFO **mib, - BLOCK_SIZE *min_block_size, - BLOCK_SIZE *max_block_size) { - int i, j; - int index = 0; + av1_invalid_rd_stats(&last_part_rdc); - // Check the sb_type for each block that belongs to this region. - for (i = 0; i < cm->seq_params.mib_size; ++i) { - for (j = 0; j < cm->seq_params.mib_size; ++j) { - MB_MODE_INFO *mi = mib[index + j]; - BLOCK_SIZE sb_type = mi ? mi->sb_type : BLOCK_4X4; - *min_block_size = AOMMIN(*min_block_size, sb_type); - *max_block_size = AOMMAX(*max_block_size, sb_type); - } - index += xd->mi_stride; + pc_tree->partitioning = partition; + + xd->above_txfm_context = cm->above_txfm_context[tile_info->tile_row] + mi_col; + xd->left_txfm_context = + xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); + save_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); + + if (bsize == BLOCK_16X16 && cpi->vaq_refresh) { + set_offsets(cpi, tile_info, x, mi_row, mi_col, bsize); + x->mb_energy = av1_log_block_var(cpi, x, bsize); } + + switch (partition) { + case PARTITION_NONE: + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, + PARTITION_NONE, bsize, ctx_none, INT64_MAX, 1); + break; + case PARTITION_HORZ: + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, + PARTITION_HORZ, subsize, &pc_tree->horizontal[0], INT64_MAX, + 1); + if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && + mi_row + hbs < cm->mi_rows) { + RD_STATS tmp_rdc; + const PICK_MODE_CONTEXT *const ctx_h = &pc_tree->horizontal[0]; + av1_init_rd_stats(&tmp_rdc); + update_state(cpi, tile_data, td, ctx_h, mi_row, mi_col, subsize, 1); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, mi_row, + mi_col, subsize, NULL); + pick_sb_modes(cpi, tile_data, x, mi_row + hbs, mi_col, &tmp_rdc, + PARTITION_HORZ, subsize, &pc_tree->horizontal[1], + INT64_MAX, 1); + if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { + av1_invalid_rd_stats(&last_part_rdc); + break; + } + last_part_rdc.rate += tmp_rdc.rate; + last_part_rdc.dist += tmp_rdc.dist; + last_part_rdc.rdcost += tmp_rdc.rdcost; + } + break; + case PARTITION_VERT: + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc, + PARTITION_VERT, subsize, &pc_tree->vertical[0], INT64_MAX, + 1); + if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && + mi_col + hbs < cm->mi_cols) { + RD_STATS tmp_rdc; + const PICK_MODE_CONTEXT *const ctx_v = &pc_tree->vertical[0]; + av1_init_rd_stats(&tmp_rdc); + update_state(cpi, tile_data, td, ctx_v, mi_row, mi_col, subsize, 1); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, mi_row, + mi_col, subsize, NULL); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + hbs, &tmp_rdc, + PARTITION_VERT, subsize, + &pc_tree->vertical[bsize > BLOCK_8X8], INT64_MAX, 1); + if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { + av1_invalid_rd_stats(&last_part_rdc); + break; + } + last_part_rdc.rate += tmp_rdc.rate; + last_part_rdc.dist += tmp_rdc.dist; + last_part_rdc.rdcost += tmp_rdc.rdcost; + } + break; + case PARTITION_SPLIT: + last_part_rdc.rate = 0; + last_part_rdc.dist = 0; + last_part_rdc.rdcost = 0; + for (i = 0; i < 4; i++) { + int x_idx = (i & 1) * hbs; + int y_idx = (i >> 1) * hbs; + int jj = i >> 1, ii = i & 0x01; + RD_STATS tmp_rdc; + if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols)) + continue; + + av1_init_rd_stats(&tmp_rdc); + nonrd_use_partition( + cpi, td, tile_data, mib + jj * hbs * cm->mi_stride + ii * hbs, tp, + mi_row + y_idx, mi_col + x_idx, subsize, &tmp_rdc.rate, + &tmp_rdc.dist, i != 3, pc_tree->split[i]); + if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) { + av1_invalid_rd_stats(&last_part_rdc); + break; + } + last_part_rdc.rate += tmp_rdc.rate; + last_part_rdc.dist += tmp_rdc.dist; + } + break; + case PARTITION_VERT_A: + case PARTITION_VERT_B: + case PARTITION_HORZ_A: + case PARTITION_HORZ_B: + case PARTITION_HORZ_4: + case PARTITION_VERT_4: + assert(0 && "Cannot handle extended partition types"); + default: assert(0); break; + } + + if (last_part_rdc.rate < INT_MAX) { + last_part_rdc.rate += x->partition_cost[pl][partition]; + last_part_rdc.rdcost = + RDCOST(x->rdmult, last_part_rdc.rate, last_part_rdc.dist); + } + + restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); + + // We must have chosen a partitioning and encoding or we'll fail later on. + // No other opportunities for success. + if (bsize == cm->seq_params.sb_size) + assert(last_part_rdc.rate < INT_MAX && last_part_rdc.dist < INT64_MAX); + + if (do_recon) { + if (bsize == cm->seq_params.sb_size) { + // NOTE: To get estimate for rate due to the tokens, use: + // int rate_coeffs = 0; + // encode_sb(cpi, td, tile_data, tp, mi_row, mi_col, DRY_RUN_COSTCOEFFS, + // bsize, pc_tree, &rate_coeffs); + x->cb_offset = 0; + encode_sb(cpi, td, tile_data, tp, mi_row, mi_col, OUTPUT_ENABLED, bsize, + pc_tree, NULL); + } else { + encode_sb(cpi, td, tile_data, tp, mi_row, mi_col, DRY_RUN_NORMAL, bsize, + pc_tree, NULL); + } + } + + *rate = last_part_rdc.rate; + *dist = last_part_rdc.dist; } // Checks to see if a super block is on a horizontal image edge. @@ -2085,238 +2171,6 @@ static int active_v_edge(const AV1_COMP *cpi, int mi_col, int mi_step) { return is_active_v_edge; } -// Checks to see if a super block is at the edge of the active image. -// In most cases this is the "real" edge unless there are formatting -// bars embedded in the stream. -static int active_edge_sb(const AV1_COMP *cpi, int mi_row, int mi_col) { - return active_h_edge(cpi, mi_row, cpi->common.seq_params.mib_size) || - active_v_edge(cpi, mi_col, cpi->common.seq_params.mib_size); -} - -// Performs a motion search in SIMPLE_TRANSLATION mode using reference frame -// ref. Note that this sets the offset of mbmi, so we will need to reset it -// after calling this function. -static void simple_motion_search(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, - int mi_col, BLOCK_SIZE bsize, int ref, - MV ref_mv_full, int num_planes, - int use_subpixel) { - assert(num_planes == 1 && - "Currently simple_motion_search only supports luma plane"); - AV1_COMMON *const cm = &cpi->common; - MACROBLOCKD *xd = &x->e_mbd; - - set_offsets(cpi, &xd->tile, x, mi_row, mi_col, bsize); - - MB_MODE_INFO *mbmi = xd->mi[0]; - mbmi->sb_type = bsize; - mbmi->ref_frame[0] = ref; - mbmi->ref_frame[1] = NONE_FRAME; - mbmi->motion_mode = SIMPLE_TRANSLATION; - - const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref); - const YV12_BUFFER_CONFIG *scaled_ref_frame = - av1_get_scaled_ref_frame(cpi, ref); - struct buf_2d backup_yv12; - // ref_mv is used to code the motion vector. ref_mv_full is the initial point. - // ref_mv is in units of 1/8 pel whereas ref_mv_full is in units of pel. - MV ref_mv = { 0, 0 }; - const int step_param = cpi->mv_step_param; - const MvLimits tmp_mv_limits = x->mv_limits; - const SEARCH_METHODS search_methods = NSTEP; - const int do_mesh_search = 0; - const int sadpb = x->sadperbit16; - int cost_list[5]; - const int ref_idx = 0; - int var; - - if (scaled_ref_frame) { - backup_yv12 = xd->plane[AOM_PLANE_Y].pre[ref_idx]; - av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL, - num_planes); - } else { - av1_setup_pre_planes(xd, ref_idx, yv12, mi_row, mi_col, - get_ref_scale_factors(cm, ref), num_planes); - } - - // This overwrites the mv_limits so we will need to restore it later. - av1_set_mv_search_range(&x->mv_limits, &ref_mv); - var = av1_full_pixel_search(cpi, x, bsize, &ref_mv_full, step_param, - search_methods, do_mesh_search, sadpb, - cond_cost_list(cpi, cost_list), &ref_mv, INT_MAX, - 1, mi_col * MI_SIZE, mi_row * MI_SIZE, 0); - // Restore - x->mv_limits = tmp_mv_limits; - - const int use_subpel_search = - var < INT_MAX && !cpi->common.cur_frame_force_integer_mv && use_subpixel; - if (use_subpel_search) { - int not_used = 0; - if (cpi->sf.use_accurate_subpel_search) { - const int pw = block_size_wide[bsize]; - const int ph = block_size_high[bsize]; - cpi->find_fractional_mv_step( - x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv, - x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop, - cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list), - x->nmv_vec_cost, x->mv_cost_stack, ¬_used, &x->pred_sse[ref], NULL, - NULL, 0, 0, pw, ph, cpi->sf.use_accurate_subpel_search, 1); - } else { - cpi->find_fractional_mv_step( - x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv, - x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop, - cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list), - x->nmv_vec_cost, x->mv_cost_stack, ¬_used, &x->pred_sse[ref], NULL, - NULL, 0, 0, 0, 0, 0, 1); - } - } else { - // Manually convert from units of pixel to 1/8-pixels if we are not doing - // subpel search - x->best_mv.as_mv.row *= 8; - x->best_mv.as_mv.col *= 8; - } - - mbmi->mv[0].as_mv = x->best_mv.as_mv; - - // Get a copy of the prediction output - set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - - aom_clear_system_state(); - - if (scaled_ref_frame) { - xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12; - } -} - -// Look at neighboring blocks and set a min and max partition size based on -// what they chose. -static void rd_auto_partition_range(AV1_COMP *cpi, const TileInfo *const tile, - MACROBLOCKD *const xd, int mi_row, - int mi_col, BLOCK_SIZE *min_block_size, - BLOCK_SIZE *max_block_size) { - AV1_COMMON *const cm = &cpi->common; - MB_MODE_INFO **mi = xd->mi; - const int left_in_image = xd->left_available && mi[-1]; - const int above_in_image = xd->up_available && mi[-xd->mi_stride]; - const int mi_rows_remaining = tile->mi_row_end - mi_row; - const int mi_cols_remaining = tile->mi_col_end - mi_col; - int bh, bw; - BLOCK_SIZE min_size = BLOCK_4X4; - BLOCK_SIZE max_size = BLOCK_LARGEST; - - // Trap case where we do not have a prediction. - if (left_in_image || above_in_image || - cm->current_frame.frame_type != KEY_FRAME) { - // Default "min to max" and "max to min" - min_size = BLOCK_LARGEST; - max_size = BLOCK_4X4; - - // NOTE: each call to get_sb_partition_size_range() uses the previous - // passed in values for min and max as a starting point. - // Find the min and max partition used in previous frame at this location - if (cm->current_frame.frame_type != KEY_FRAME) { - MB_MODE_INFO **prev_mi = - &cm->prev_mi_grid_visible[mi_row * xd->mi_stride + mi_col]; - get_sb_partition_size_range(cm, xd, prev_mi, &min_size, &max_size); - } - // Find the min and max partition sizes used in the left superblock - if (left_in_image) { - MB_MODE_INFO **left_sb_mi = &mi[-cm->seq_params.mib_size]; - get_sb_partition_size_range(cm, xd, left_sb_mi, &min_size, &max_size); - } - // Find the min and max partition sizes used in the above suprblock. - if (above_in_image) { - MB_MODE_INFO **above_sb_mi = - &mi[-xd->mi_stride * cm->seq_params.mib_size]; - get_sb_partition_size_range(cm, xd, above_sb_mi, &min_size, &max_size); - } - - // Adjust observed min and max for "relaxed" auto partition case. - if (cpi->sf.auto_min_max_partition_size == RELAXED_NEIGHBORING_MIN_MAX) { - min_size = min_partition_size[min_size]; - max_size = max_partition_size[max_size]; - } - } - - // Check border cases where max and min from neighbors may not be legal. - max_size = find_partition_size(max_size, mi_rows_remaining, mi_cols_remaining, - &bh, &bw); - min_size = AOMMIN(min_size, max_size); - - // Test for blocks at the edge of the active image. - // This may be the actual edge of the image or where there are formatting - // bars. - if (active_edge_sb(cpi, mi_row, mi_col)) { - min_size = BLOCK_4X4; - } else { - min_size = AOMMIN(cpi->sf.rd_auto_partition_min_limit, min_size); - } - - // When use_square_partition_only is true, make sure at least one square - // partition is allowed by selecting the next smaller square size as - // *min_block_size. - if (min_size >= cpi->sf.use_square_partition_only_threshold) { - min_size = AOMMIN(min_size, next_square_size[max_size]); - } - - *min_block_size = AOMMIN(min_size, cm->seq_params.sb_size); - *max_block_size = AOMMIN(max_size, cm->seq_params.sb_size); -} - -// TODO(jingning) refactor functions setting partition search range -static void set_partition_range(const AV1_COMMON *const cm, - const MACROBLOCKD *const xd, int mi_row, - int mi_col, BLOCK_SIZE bsize, - BLOCK_SIZE *const min_bs, - BLOCK_SIZE *const max_bs) { - const int mi_width = mi_size_wide[bsize]; - const int mi_height = mi_size_high[bsize]; - int idx, idy; - - const int idx_str = cm->mi_stride * mi_row + mi_col; - MB_MODE_INFO **const prev_mi = &cm->prev_mi_grid_visible[idx_str]; - BLOCK_SIZE min_size = cm->seq_params.sb_size; // default values - BLOCK_SIZE max_size = BLOCK_4X4; - - if (prev_mi) { - for (idy = 0; idy < mi_height; ++idy) { - for (idx = 0; idx < mi_width; ++idx) { - const MB_MODE_INFO *const mi = prev_mi[idy * cm->mi_stride + idx]; - const BLOCK_SIZE bs = mi ? mi->sb_type : bsize; - min_size = AOMMIN(min_size, bs); - max_size = AOMMAX(max_size, bs); - } - } - } - - if (xd->left_available) { - for (idy = 0; idy < mi_height; ++idy) { - const MB_MODE_INFO *const mi = xd->mi[idy * cm->mi_stride - 1]; - const BLOCK_SIZE bs = mi ? mi->sb_type : bsize; - min_size = AOMMIN(min_size, bs); - max_size = AOMMAX(max_size, bs); - } - } - - if (xd->up_available) { - for (idx = 0; idx < mi_width; ++idx) { - const MB_MODE_INFO *const mi = xd->mi[idx - cm->mi_stride]; - const BLOCK_SIZE bs = mi ? mi->sb_type : bsize; - min_size = AOMMIN(min_size, bs); - max_size = AOMMAX(max_size, bs); - } - } - - if (min_size == max_size) { - min_size = min_partition_size[min_size]; - max_size = max_partition_size[max_size]; - } - - *min_bs = AOMMIN(min_size, cm->seq_params.sb_size); - *max_bs = AOMMIN(max_size, cm->seq_params.sb_size); -} - static INLINE void store_pred_mv(MACROBLOCK *x, PICK_MODE_CONTEXT *ctx) { memcpy(ctx->pred_mv, x->pred_mv, sizeof(x->pred_mv)); } @@ -2326,56 +2180,6 @@ static INLINE void load_pred_mv(MACROBLOCK *x, memcpy(x->pred_mv, ctx->pred_mv, sizeof(x->pred_mv)); } -#if CONFIG_FP_MB_STATS -const int qindex_skip_threshold_lookup[BLOCK_SIZES] = { - 0, 10, 10, 30, 40, 40, 60, 80, 80, 90, 100, 100, 120, - // TODO(debargha): What are the correct numbers here? - 130, 130, 150 -}; -const int qindex_split_threshold_lookup[BLOCK_SIZES] = { - 0, 3, 3, 7, 15, 15, 30, 40, 40, 60, 80, 80, 120, - // TODO(debargha): What are the correct numbers here? - 160, 160, 240 -}; -const int complexity_16x16_blocks_threshold[BLOCK_SIZES] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 6, - // TODO(debargha): What are the correct numbers here? - 8, 8, 10 -}; - -enum { - MV_ZERO = 0, - MV_LEFT = 1, - MV_UP = 2, - MV_RIGHT = 3, - MV_DOWN = 4, - MV_INVALID -} UENUM1BYTE(MOTION_DIRECTION); - -static INLINE MOTION_DIRECTION get_motion_direction_fp(uint8_t fp_byte) { - if (fp_byte & FPMB_MOTION_ZERO_MASK) { - return MV_ZERO; - } else if (fp_byte & FPMB_MOTION_LEFT_MASK) { - return MV_LEFT; - } else if (fp_byte & FPMB_MOTION_RIGHT_MASK) { - return MV_RIGHT; - } else if (fp_byte & FPMB_MOTION_UP_MASK) { - return MV_UP; - } else { - return MV_DOWN; - } -} - -static INLINE int get_motion_inconsistency(MOTION_DIRECTION this_mv, - MOTION_DIRECTION that_mv) { - if (this_mv == that_mv) { - return 0; - } else { - return abs(this_mv - that_mv) == 2 ? 2 : 1; - } -} -#endif - // Try searching for an encoding for the given subblock. Returns zero if the // rdcost is already too high (to tell the caller not to bother searching for // encodings of further subblocks) @@ -2397,9 +2201,9 @@ static int rd_try_subblock(AV1_COMP *const cpi, ThreadData *td, ? INT64_MAX : (best_rdc->rdcost - sum_rdc->rdcost); - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, this_rdc, - RTS_X_RATE_NOCOEF_ARG partition, subsize, this_ctx, - rdcost_remaining); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, this_rdc, + RTS_X_RATE_NOCOEF_ARG partition, subsize, this_ctx, + rdcost_remaining, 0); if (this_rdc->rate == INT_MAX) { sum_rdc->rdcost = INT64_MAX; @@ -2615,8 +2419,8 @@ static void rd_pick_sqr_partition(AV1_COMP *const cpi, ThreadData *td, const int64_t best_remain_rdcost = best_rdc.rdcost == INT64_MAX ? INT64_MAX : (best_rdc.rdcost - partition_rd_cost); - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, - PARTITION_NONE, bsize, ctx_none, best_remain_rdcost); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, PARTITION_NONE, + bsize, ctx_none, best_remain_rdcost, 0); pc_tree->pc_tree_stats.rdcost = ctx_none->rdcost; pc_tree->pc_tree_stats.skip = ctx_none->skip; @@ -2668,6 +2472,17 @@ static void rd_pick_sqr_partition(AV1_COMP *const cpi, ThreadData *td, do_square_split = 0; } } + + if (cpi->sf.firstpass_simple_motion_search_early_term && + cm->show_frame && bsize <= BLOCK_32X32 && bsize >= BLOCK_8X8 && + !frame_is_intra_only(cm) && mi_row + mi_step < cm->mi_rows && + mi_col + mi_step < cm->mi_cols && this_rdc.rdcost < INT64_MAX && + this_rdc.rdcost >= 0 && this_rdc.rate < INT_MAX && + this_rdc.rate >= 0 && do_square_split) { + av1_firstpass_simple_motion_search_early_term( + cpi, x, pc_tree, mi_row, mi_col, bsize, &this_rdc, + &do_square_split); + } } } @@ -2789,6 +2604,7 @@ static void rd_pick_sqr_partition(AV1_COMP *const cpi, ThreadData *td, // split_score indicates confidence of picking split partition; // none_score indicates confidence of picking none partition; +#define FEATURE_SIZE 19 static int ml_prune_2pass_split_partition(const PC_TREE_STATS *pc_tree_stats, BLOCK_SIZE bsize, int *split_score, int *none_score) { @@ -2798,24 +2614,24 @@ static int ml_prune_2pass_split_partition(const PC_TREE_STATS *pc_tree_stats, switch (bsize) { case BLOCK_4X4: break; case BLOCK_8X8: - split_weights = two_pass_split_partition_weights_8; - none_weights = two_pass_none_partition_weights_8; + split_weights = av1_2pass_split_partition_weights_8; + none_weights = av1_2pass_none_partition_weights_8; break; case BLOCK_16X16: - split_weights = two_pass_split_partition_weights_16; - none_weights = two_pass_none_partition_weights_16; + split_weights = av1_2pass_split_partition_weights_16; + none_weights = av1_2pass_none_partition_weights_16; break; case BLOCK_32X32: - split_weights = two_pass_split_partition_weights_32; - none_weights = two_pass_none_partition_weights_32; + split_weights = av1_2pass_split_partition_weights_32; + none_weights = av1_2pass_none_partition_weights_32; break; case BLOCK_64X64: - split_weights = two_pass_split_partition_weights_64; - none_weights = two_pass_none_partition_weights_64; + split_weights = av1_2pass_split_partition_weights_64; + none_weights = av1_2pass_none_partition_weights_64; break; case BLOCK_128X128: - split_weights = two_pass_split_partition_weights_128; - none_weights = two_pass_none_partition_weights_128; + split_weights = av1_2pass_split_partition_weights_128; + none_weights = av1_2pass_none_partition_weights_128; break; default: assert(0 && "Unexpected bsize."); } @@ -3268,484 +3084,28 @@ static int ml_predict_breakout(const AV1_COMP *const cpi, BLOCK_SIZE bsize, } #undef FEATURES -#if CONFIG_ONE_PASS_SVM -#define FEATURES 24 -static void ml_op_svm_early_term(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - const MACROBLOCKD *const xd, - const PICK_MODE_CONTEXT *ctx_none, - const RD_STATS *none_rdc, int pb_source_var, - BLOCK_SIZE bsize, float *const score) { - const float *ml_weights = NULL, *ml_mean = NULL, *ml_std = NULL; - if (bsize == BLOCK_128X128) { - ml_weights = av1_op_svm_early_term_weights_128; - ml_mean = av1_op_svm_early_term_mean_128; - ml_std = av1_op_svm_early_term_std_128; - } else if (bsize == BLOCK_64X64) { - ml_weights = av1_op_svm_early_term_weights_64; - ml_mean = av1_op_svm_early_term_mean_64; - ml_std = av1_op_svm_early_term_std_64; - } else if (bsize == BLOCK_32X32) { - ml_weights = av1_op_svm_early_term_weights_32; - ml_mean = av1_op_svm_early_term_mean_32; - ml_std = av1_op_svm_early_term_std_32; - } else if (bsize == BLOCK_16X16) { - ml_weights = av1_op_svm_early_term_weights_16; - ml_mean = av1_op_svm_early_term_mean_16; - ml_std = av1_op_svm_early_term_std_16; - } else { - assert(bsize == BLOCK_128X128 || bsize == BLOCK_64X64 || - bsize == BLOCK_32X32 || bsize == BLOCK_8X8); - } - if (ml_weights != NULL) { - // Compute some features - - float features[FEATURES] = { 0 }; - int f_idx = 0; - int r_idx = 0; - - // None features - // Get none stats - features[f_idx++] = none_rdc->rate; - features[f_idx++] = none_rdc->dist; - features[f_idx++] = none_rdc->rdcost; - features[f_idx++] = ctx_none->skip; - - // EOBS - features[f_idx++] = none_rdc->eob; - int scaled_eob = none_rdc->eob * 32 * 32; - features[f_idx++] = (1.0f + none_rdc->eob_0) / (4.0f + scaled_eob); - features[f_idx++] = (1.0f + none_rdc->eob_1) / (4.0f + scaled_eob); - features[f_idx++] = (1.0f + none_rdc->eob_2) / (4.0f + scaled_eob); - features[f_idx++] = (1.0f + none_rdc->eob_3) / (4.0f + scaled_eob); - - // Y_RD - features[f_idx++] = none_rdc->rd; - int64_t scaled_rd = none_rdc->rd * 32 * 32; - features[f_idx++] = (1.0f + none_rdc->rd_0) / (4.0f + scaled_rd); - features[f_idx++] = (1.0f + none_rdc->rd_1) / (4.0f + scaled_rd); - features[f_idx++] = (1.0f + none_rdc->rd_2) / (4.0f + scaled_rd); - features[f_idx++] = (1.0f + none_rdc->rd_3) / (4.0f + scaled_rd); - - // Q_SQUARED - features[f_idx++] = - (x->plane[0].dequant_QTX[0]) * (x->plane[0].dequant_QTX[0]); - - // SIZE - // Get size of surrounding blocks - int above_size = 18, left_size = 18; - const MB_MODE_INFO *above_block = xd->above_mbmi; - const MB_MODE_INFO *left_block = xd->left_mbmi; - - if (above_block) { - above_size = above_block->sb_type; - } - if (left_block) { - left_size = left_block->sb_type; - } - - features[f_idx++] = left_size; - features[f_idx++] = left_size != 18; - - features[f_idx++] = above_size; - features[f_idx++] = above_size != 18; - - // Variance - // Get variance - int var = pb_source_var, var_reg[4] = { 0 }; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const BLOCK_SIZE split_size = get_partition_subsize(bsize, PARTITION_SPLIT); - struct buf_2d buf; - buf.stride = x->plane[0].src.stride; - for (int i = 0; i < 4; ++i) { - const int x_idx = (i & 1) * bw / 2; - const int y_idx = (i >> 1) * bh / 2; - buf.buf = x->plane[0].src.buf + x_idx + y_idx * buf.stride; - if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { - var_reg[i] = - av1_high_get_sby_perpixel_variance(cpi, &buf, split_size, xd->bd); - } else { - var_reg[i] = av1_get_sby_perpixel_variance(cpi, &buf, split_size); - } - } - - features[f_idx++] = var; - for (r_idx = 0; r_idx < 4; r_idx++) { - features[f_idx] = (var_reg[r_idx] + 1.0f) / (var + 4.0f); - f_idx++; - } - - assert(f_idx == FEATURES); - - // Calculate the score - *score = 0.0f; - for (f_idx = 0; f_idx < FEATURES; f_idx++) { - *score += ml_weights[f_idx] * (features[f_idx] - ml_mean[f_idx]) / - ml_std[f_idx]; - } - // Dont forget the bias - *score += ml_weights[FEATURES]; - } -} -#undef FEATURES -#endif - -// Performs a full_pixel_motion_search with a single reference frame and extract -// the variance of residues. Here features is assumed to be a length 6 array. -// After this function is called, we will store the following in to features: -// features[0] = log(1 + dc_q**2/256) -// features[1] = log(1 + variance_of_residue) -// for i in [2, 3, 4, 5]: -// features[i] = log(1 + variance_of_residue_in_block[i]/variance_of_residue) -static void get_res_var_features(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, - int mi_col, BLOCK_SIZE bsize, - float *features) { - // TODO(chiyotsai@google.com): The data this model trained on did not also use - // SIMPLE_TRANSLATION to build the inter_predictor. Retraining and tuning the - // model with the correct data should give better performance. +// Record the ref frames that have been selected by square partition blocks. +static void update_picked_ref_frames_mask(MACROBLOCK *const x, int ref_type, + BLOCK_SIZE bsize, int mib_size, + int mi_row, int mi_col) { assert(mi_size_wide[bsize] == mi_size_high[bsize]); - - MACROBLOCKD *xd = &x->e_mbd; - - // Perform a single motion search in Y_PLANE to make a prediction - const MV_REFERENCE_FRAME ref = - cpi->rc.is_src_frame_alt_ref ? ALTREF_FRAME : LAST_FRAME; - const int use_subpixel = 0; - const int num_planes = 1; - - const MV ref_mv_full = { .row = 0, .col = 0 }; - simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, ref_mv_full, - num_planes, use_subpixel); - aom_clear_system_state(); - - // Start getting the features - int f_idx = 0; - - // Q_INDEX - const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); - features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f); - - // VARIANCE - const uint8_t *src = x->plane[0].src.buf; - const int src_stride = x->plane[0].src.stride; - const uint8_t *dst = xd->plane[0].dst.buf; - const int dst_stride = xd->plane[0].dst.stride; - unsigned int sse = 0; - - // Whole block - const unsigned int var = - cpi->fn_ptr[bsize].vf(src, src_stride, dst, dst_stride, &sse); - features[f_idx++] = logf(1.0f + (float)var); - - // Regional - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT); - int r_idx = 0; - for (r_idx = 0; r_idx < 4; r_idx++) { - const int x_idx = (r_idx & 1) * bw / 2; - const int y_idx = (r_idx >> 1) * bh / 2; - const int src_offset = y_idx * src_stride + x_idx; - const int dst_offset = y_idx * dst_stride + x_idx; - const unsigned int sub_var = cpi->fn_ptr[subsize].vf( - src + src_offset, src_stride, dst + dst_offset, dst_stride, &sse); - const float var_ratio = (1.0f + (float)sub_var) / (4.0f + (float)var); - features[f_idx++] = var_ratio; - } -} - -static void full_pixel_motion_search_based_split( - AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, int mi_col, - BLOCK_SIZE bsize, int *partition_none_allowed, int *partition_horz_allowed, - int *partition_vert_allowed, int *do_rectangular_split) { - const NN_CONFIG *nn_config = NULL; - float split_only_thresh = 0.0f; - if (bsize == BLOCK_128X128) { - nn_config = &full_pixel_motion_search_based_split_nn_config_128; - split_only_thresh = full_pixel_motion_search_based_split_thresh_128; - } else if (bsize == BLOCK_64X64) { - nn_config = &full_pixel_motion_search_based_split_nn_config_64; - split_only_thresh = full_pixel_motion_search_based_split_thresh_64; - } else if (bsize == BLOCK_32X32) { - nn_config = &full_pixel_motion_search_based_split_nn_config_32; - split_only_thresh = full_pixel_motion_search_based_split_thresh_32; - } else if (bsize == BLOCK_16X16) { - nn_config = &full_pixel_motion_search_based_split_nn_config_16; - split_only_thresh = full_pixel_motion_search_based_split_thresh_16; - } else if (bsize == BLOCK_8X8) { - // Disable BLOCK_8X8 for now -#if !CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 - nn_config = &full_pixel_motion_search_based_split_nn_config_8; - split_only_thresh = full_pixel_motion_search_based_split_thresh_8; -#endif - } else { - assert(0 && "Unexpected block size in full_pixel_motion_based_split"); - } - if (nn_config) { - float features[6] = { 0 }; - float score = 0; - get_res_var_features(cpi, x, mi_row, mi_col, bsize, features); - av1_nn_predict(features, nn_config, &score); - - if (score > split_only_thresh) { - *partition_none_allowed = 0; - *partition_horz_allowed = 0; - *partition_vert_allowed = 0; - *do_rectangular_split = 0; + const int sb_size_mask = mib_size - 1; + const int mi_row_in_sb = mi_row & sb_size_mask; + const int mi_col_in_sb = mi_col & sb_size_mask; + const int mi_size = mi_size_wide[bsize]; + for (int i = mi_row_in_sb; i < mi_row_in_sb + mi_size; ++i) { + for (int j = mi_col_in_sb; j < mi_col_in_sb + mi_size; ++j) { + x->picked_ref_frames_mask[i * 32 + j] |= 1 << ref_type; } } } -// Given a list of ref frames in refs, performs simple_motion_search on each of -// the refs and returns the ref with the smallest sse. Returns -1 if none of the -// ref in the list is available. Also stores the best sse and var in best_sse, -// best_var, respectively. If save_mv_code is -1, don't update mv_ref_fulls in -// pc_tree. If save_mv_code is between 0 and 3, update mv_ref_fulls under -// pc_tree->split[i]. If save_mv_code is 4, update mv_ref_fulls under pc_tree. -static int simple_motion_search_get_best_ref( - AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, - int mi_col, BLOCK_SIZE bsize, const int *const refs, int num_refs, - int use_subpixel, int save_mv_code, unsigned int *best_sse, - unsigned int *best_var) { - // TODO(chiyotsai@google.com): The calculation of variance currently uses - // bsize, so we might take area outside of the image into account. We need to - // modify the SIMD functions to fix this later. - const AV1_COMMON *const cm = &cpi->common; - int best_ref = -1; - - if (mi_col >= cm->mi_cols || mi_row >= cm->mi_rows) { - // If the whole block is outside of the image, set the var and sse to 0. - *best_var = 0; - *best_sse = 0; - - return best_ref; - } - - // Otherwise do loop through the reference frames and find the one with the - // minimum SSE - const MACROBLOCKD *xd = &x->e_mbd; - const MV *mv_ref_fulls = pc_tree->mv_ref_fulls; - - const int num_planes = 1; - - *best_sse = INT_MAX; - - for (int ref_idx = 0; ref_idx < num_refs; ref_idx++) { - const int ref = refs[ref_idx]; - - if (cpi->ref_frame_flags & ref_frame_flag_list[ref]) { - unsigned int curr_sse = 0, curr_var = 0; - simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, - mv_ref_fulls[ref], num_planes, use_subpixel); - curr_var = cpi->fn_ptr[bsize].vf( - x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].dst.buf, - xd->plane[0].dst.stride, &curr_sse); - if (curr_sse < *best_sse) { - *best_sse = curr_sse; - *best_var = curr_var; - best_ref = ref; - } - - if (save_mv_code == 4) { - pc_tree->mv_ref_fulls[ref].row = x->best_mv.as_mv.row / 8; - pc_tree->mv_ref_fulls[ref].col = x->best_mv.as_mv.col / 8; - } else if (save_mv_code >= 0 && save_mv_code < 4) { - // Propagate the new motion vectors to a lower level - pc_tree->split[save_mv_code]->mv_ref_fulls[ref].row = - x->best_mv.as_mv.row / 8; - pc_tree->split[save_mv_code]->mv_ref_fulls[ref].col = - x->best_mv.as_mv.col / 8; - } - } - } - - return best_ref; -} - -// Performs fullpixel simple_motion_search with LAST_FRAME and ALTREF_FRAME on -// each subblocks and extract the variance and sse of residues. Then store the -// var and sse from each partition subblock to features. The DC qindex is also -// stored in features. -// Here features is assumed to be a length 19 array. -// After this function is called, we will store the following to features: -// features[0:17] = var and sse from subblocks -// features[18] = DC q_index -#define NUM_FEATURES 19 -static void simple_motion_search_prune_part_features( - AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, - int mi_col, BLOCK_SIZE bsize, float *features) { - // TODO(chiyotsai@google.com): Cache the result of the motion search from the - // larger bbsize. - const int w_mi = mi_size_wide[bsize]; - const int h_mi = mi_size_high[bsize]; - int f_idx = 0; - assert(mi_size_wide[bsize] == mi_size_high[bsize]); - assert(cpi->ref_frame_flags & ref_frame_flag_list[LAST_FRAME] || - cpi->ref_frame_flags & ref_frame_flag_list[ALTREF_FRAME]); - - // Setting up motion search - const int ref_list[] = { LAST_FRAME, ALTREF_FRAME }; - const int num_refs = 2; - const int use_subpixel = 0; - - unsigned int none_sse = 0, none_var = 0; - unsigned int int_features[NUM_FEATURES - 1]; - - // Doing whole block first to update the mv - simple_motion_search_get_best_ref(cpi, x, pc_tree, mi_row, mi_col, bsize, - ref_list, num_refs, use_subpixel, 4, - &none_sse, &none_var); - - // Split subblocks - BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT); - int r_idx = 0; - for (r_idx = 0; r_idx < 4; r_idx++) { - const int sub_mi_col = mi_col + (r_idx & 1) * w_mi / 2; - const int sub_mi_row = mi_row + (r_idx >> 1) * h_mi / 2; - - simple_motion_search_get_best_ref( - cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, - use_subpixel, r_idx, &int_features[f_idx + 1], &int_features[f_idx]); - f_idx += 2; - } - - // Horz subblocks - subsize = get_partition_subsize(bsize, PARTITION_HORZ); - for (r_idx = 0; r_idx < 2; r_idx++) { - const int sub_mi_col = mi_col + 0; - const int sub_mi_row = mi_row + r_idx * h_mi / 2; - - simple_motion_search_get_best_ref( - cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, - use_subpixel, -1, &int_features[f_idx + 1], &int_features[f_idx]); - - f_idx += 2; - } - - // Vert subblock - subsize = get_partition_subsize(bsize, PARTITION_VERT); - for (r_idx = 0; r_idx < 2; r_idx++) { - const int sub_mi_col = mi_col + r_idx * w_mi / 2; - const int sub_mi_row = mi_row + 0; - - simple_motion_search_get_best_ref( - cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, - use_subpixel, -1, &int_features[f_idx + 1], &int_features[f_idx]); - - f_idx += 2; - } - - // Whole block - int_features[f_idx++] = none_var; - int_features[f_idx++] = none_sse; - - aom_clear_system_state(); - for (int idx = 0; idx < f_idx; idx++) { - features[idx] = logf(1.0f + (float)int_features[idx]); - } - - const MACROBLOCKD *xd = &x->e_mbd; - set_offsets(cpi, &xd->tile, x, mi_row, mi_col, bsize); - - // Q_INDEX - const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); - features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f); - - assert(f_idx == NUM_FEATURES); -} - -#define MAX_NUM_CLASSES 10 -static void simple_motion_search_prune_part( - AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, - int mi_col, BLOCK_SIZE bsize, int *partition_none_allowed, - int *partition_horz_allowed, int *partition_vert_allowed, - int *do_square_split, int *do_rectangular_split, int *prune_horz, - int *prune_vert) { - const AV1_COMMON *const cm = &cpi->common; - // Get model parameters - const NN_CONFIG *nn_config = NULL; - const float *prune_thresh = NULL, *only_thresh = NULL; - const float *ml_mean = NULL, *ml_std = NULL; - - if (bsize == BLOCK_128X128) { - nn_config = &simple_motion_search_prune_part_nn_config_128; - ml_mean = simple_motion_search_prune_part_mean_128; - ml_std = simple_motion_search_prune_part_std_128; - prune_thresh = simple_motion_search_prune_part_prune_thresh_128; - only_thresh = simple_motion_search_prune_part_only_thresh_128; - } else if (bsize == BLOCK_64X64) { - nn_config = &simple_motion_search_prune_part_nn_config_64; - ml_mean = simple_motion_search_prune_part_mean_64; - ml_std = simple_motion_search_prune_part_std_64; - prune_thresh = simple_motion_search_prune_part_prune_thresh_64; - only_thresh = simple_motion_search_prune_part_only_thresh_64; - } else if (bsize == BLOCK_32X32) { - nn_config = &simple_motion_search_prune_part_nn_config_32; - ml_mean = simple_motion_search_prune_part_mean_32; - ml_std = simple_motion_search_prune_part_std_32; - prune_thresh = simple_motion_search_prune_part_prune_thresh_32; - only_thresh = simple_motion_search_prune_part_only_thresh_32; - } else if (bsize == BLOCK_16X16) { - nn_config = &simple_motion_search_prune_part_nn_config_16; - ml_mean = simple_motion_search_prune_part_mean_16; - ml_std = simple_motion_search_prune_part_std_16; - prune_thresh = simple_motion_search_prune_part_prune_thresh_16; - only_thresh = simple_motion_search_prune_part_only_thresh_16; - } else if (bsize == BLOCK_8X8) { - nn_config = &simple_motion_search_prune_part_nn_config_8; - ml_mean = simple_motion_search_prune_part_mean_8; - ml_std = simple_motion_search_prune_part_std_8; - prune_thresh = simple_motion_search_prune_part_prune_thresh_8; - only_thresh = simple_motion_search_prune_part_only_thresh_8; - } else { - assert(0 && "Unexpected block size in simple_motion_prune_part"); - } - - // If there is no valid threshold, return immediately. - if (!nn_config || (prune_thresh[PARTITION_HORZ] == 0.0f && - prune_thresh[PARTITION_VERT] == 0.0f)) { - return; - } - - // Get features - float features[NUM_FEATURES] = { 0.0f }; - simple_motion_search_prune_part_features(cpi, x, pc_tree, mi_row, mi_col, - bsize, features); - for (int f_idx = 0; f_idx < NUM_FEATURES; f_idx++) { - features[f_idx] = (features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx]; - } - - // Get probabilities - float scores[MAX_NUM_CLASSES] = { 0.0f }, probs[MAX_NUM_CLASSES] = { 0.0f }; - const int num_classes = - (bsize == BLOCK_128X128 || bsize == BLOCK_8X8) ? 4 : 10; - - av1_nn_predict(features, nn_config, scores); - aom_clear_system_state(); - - av1_nn_softmax(scores, probs, num_classes); - - // Determine if we should prune rectangular partitions. - if (cpi->sf.simple_motion_search_prune_rect && !frame_is_intra_only(cm) && - (*partition_horz_allowed || *partition_vert_allowed) && - bsize >= BLOCK_8X8 && !av1_superres_scaled(cm)) { - *prune_horz = probs[PARTITION_HORZ] <= prune_thresh[PARTITION_HORZ]; - *prune_vert = probs[PARTITION_VERT] <= prune_thresh[PARTITION_VERT]; - } - - // Silence compiler warnings - (void)only_thresh; - (void)partition_none_allowed; - (void)do_square_split; - (void)do_rectangular_split; -} -#undef MAX_NUM_CLASSES -#undef NUM_FEATURES - // TODO(jinging,jimbankoski,rbultje): properly skip partition types that are // unlikely to be selected depending on previous rate-distortion optimization // results, for encoding speed-up. +// TODO(chiyotsai@google.com): Move these ml related varables to a seprate file +// to separate low level ml logic from partition logic +#define NUM_SIMPLE_MOTION_FEATURES 28 static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, TileDataEnc *tile_data, TOKENEXTRA **tp, int mi_row, int mi_col, BLOCK_SIZE bsize, @@ -3779,22 +3139,13 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, int64_t vert_rd[2] = { 0, 0 }; int prune_horz = 0; int prune_vert = 0; + int terminate_partition_search = 0; int split_ctx_is_ready[2] = { 0, 0 }; int horz_ctx_is_ready = 0; int vert_ctx_is_ready = 0; BLOCK_SIZE bsize2 = get_partition_subsize(bsize, PARTITION_SPLIT); - // Max and min square partition levels are defined as the partition nodes that - // the recursive function rd_pick_partition() can reach. To implement this: - // only PARTITION_SPLIT is NOT allowed if the current node equals min_sq_part, - // only PARTITION_SPLIT is allowed if the current node exceeds max_sq_part. - assert(block_size_wide[min_sq_part] == block_size_high[min_sq_part]); - assert(block_size_wide[max_sq_part] == block_size_high[max_sq_part]); - assert(min_sq_part <= max_sq_part); - int is_eq_min_sq_part = bsize == min_sq_part; - int is_gt_max_sq_part = bsize > max_sq_part; - if (best_rd < 0) { pc_tree->none.rdcost = INT64_MAX; pc_tree->none.skip = 0; @@ -3809,16 +3160,7 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, const int xss = x->e_mbd.plane[1].subsampling_x; const int yss = x->e_mbd.plane[1].subsampling_y; - BLOCK_SIZE min_size = x->min_partition_size; - BLOCK_SIZE max_size = x->max_partition_size; - if (none_rd) *none_rd = 0; - -#if CONFIG_FP_MB_STATS - unsigned int src_diff_var = UINT_MAX; - int none_complexity = 0; -#endif - int partition_none_allowed = has_rows && has_cols; int partition_horz_allowed = has_cols && yss <= xss && bsize_at_least_8x8 && cpi->oxcf.enable_rect_partitions; @@ -3828,10 +3170,14 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, (void)*tp_orig; #if CONFIG_COLLECT_PARTITION_STATS + int partition_decisions[EXT_PARTITION_TYPES] = { 0 }; + int partition_attempts[EXT_PARTITION_TYPES] = { 0 }; + int64_t partition_times[EXT_PARTITION_TYPES] = { 0 }; + struct aom_usec_timer partition_timer = { 0 }; + int partition_timer_on = 0; +#if CONFIG_COLLECT_PARTITION_STATS == 2 PartitionStats *part_stats = &cpi->partition_stats; - const int bsize_idx = av1_get_bsize_idx_for_part_stats(bsize); - int *partition_decisions = part_stats->partition_decisions[bsize_idx]; - int *partition_attempts = part_stats->partition_attempts[bsize_idx]; +#endif #endif // Override partition costs at the edges of the frame in the same @@ -3858,6 +3204,7 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, } partition_cost = tmp_partition_cost; + do_square_split &= partition_cost[PARTITION_SPLIT] != INT_MAX; } #ifndef NDEBUG @@ -3880,35 +3227,12 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, if (bsize == BLOCK_16X16 && cpi->vaq_refresh) x->mb_energy = av1_log_block_var(cpi, x, bsize); - if (cpi->sf.cb_partition_search && bsize == BLOCK_16X16) { - const int cb_partition_search_ctrl = - ((pc_tree->index == 0 || pc_tree->index == 3) + - get_chessboard_index(cm->current_frame.frame_number)) & - 0x1; - - if (cb_partition_search_ctrl && bsize > min_size && bsize < max_size) - set_partition_range(cm, xd, mi_row, mi_col, bsize, &min_size, &max_size); - } - - // Determine partition types in search according to the speed features. - // The threshold set here has to be of square block size. - if (cpi->sf.auto_min_max_partition_size) { - const int no_partition_allowed = (bsize <= max_size && bsize >= min_size); - // Note: Further partitioning is NOT allowed when bsize == min_size already. - const int partition_allowed = (bsize <= max_size && bsize > min_size); - partition_none_allowed &= no_partition_allowed; - partition_horz_allowed &= partition_allowed || !has_rows; - partition_vert_allowed &= partition_allowed || !has_cols; - do_square_split &= bsize > min_size; - } - if (bsize > cpi->sf.use_square_partition_only_threshold) { partition_horz_allowed &= !has_rows; partition_vert_allowed &= !has_cols; } - if (bsize > BLOCK_4X4 && x->use_cb_search_range && - cpi->sf.auto_min_max_partition_size == 0) { + if (bsize > BLOCK_4X4 && x->use_cb_search_range) { int split_score = 0; int none_score = 0; const int score_valid = ml_prune_2pass_split_partition( @@ -3965,71 +3289,6 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); save_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - set_offsets(cpi, tile_info, x, mi_row, mi_col, bsize); - src_diff_var = get_sby_perpixel_diff_variance(cpi, &x->plane[0].src, mi_row, - mi_col, bsize); - } - - // Decide whether we shall split directly and skip searching NONE by using - // the first pass block statistics - if (cpi->use_fp_mb_stats && bsize >= BLOCK_32X32 && do_square_split && - partition_none_allowed && src_diff_var > 4 && - cm->base_qindex < qindex_split_threshold_lookup[bsize]) { - int mb_row = mi_row >> 1; - int mb_col = mi_col >> 1; - int mb_row_end = - AOMMIN(mb_row + num_16x16_blocks_high_lookup[bsize], cm->mb_rows); - int mb_col_end = - AOMMIN(mb_col + num_16x16_blocks_wide_lookup[bsize], cm->mb_cols); - int r, c; - - // compute a complexity measure, basically measure inconsistency of motion - // vectors obtained from the first pass in the current block - for (r = mb_row; r < mb_row_end; r++) { - for (c = mb_col; c < mb_col_end; c++) { - const int mb_index = r * cm->mb_cols + c; - - MOTION_DIRECTION this_mv; - MOTION_DIRECTION right_mv; - MOTION_DIRECTION bottom_mv; - - this_mv = - get_motion_direction_fp(cpi->twopass.this_frame_mb_stats[mb_index]); - - // to its right - if (c != mb_col_end - 1) { - right_mv = get_motion_direction_fp( - cpi->twopass.this_frame_mb_stats[mb_index + 1]); - none_complexity += get_motion_inconsistency(this_mv, right_mv); - } - - // to its bottom - if (r != mb_row_end - 1) { - bottom_mv = get_motion_direction_fp( - cpi->twopass.this_frame_mb_stats[mb_index + cm->mb_cols]); - none_complexity += get_motion_inconsistency(this_mv, bottom_mv); - } - - // do not count its left and top neighbors to avoid double counting - } - } - - if (none_complexity > complexity_16x16_blocks_threshold[bsize]) { - partition_none_allowed = 0; - } - } -#endif - - // Ref frames picked in the [i_th] quarter subblock during square partition - // RD search. It may be used to prune ref frame selection of rect partitions. - int ref_frames_used[4] = { - 0, - }; - - MB_MODE_INFO *split_mbmi[4] = { 0 }; - // Use simple_motion_search to prune partitions. This must be done prior to // PARTITION_SPLIT to propagate the initial mvs to a smaller blocksize. const int try_split_only = @@ -4039,35 +3298,82 @@ static void rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, !av1_superres_scaled(cm); if (try_split_only) { - full_pixel_motion_search_based_split( + av1_simple_motion_search_based_split( cpi, x, mi_row, mi_col, bsize, &partition_none_allowed, - &partition_horz_allowed, &partition_vert_allowed, - &do_rectangular_split); + &partition_horz_allowed, &partition_vert_allowed, &do_rectangular_split, + &do_square_split); } const int try_prune_rect = cpi->sf.simple_motion_search_prune_rect && !frame_is_intra_only(cm) && + do_rectangular_split && + (do_square_split || partition_none_allowed || + (prune_horz && prune_vert)) && (partition_horz_allowed || partition_vert_allowed) && bsize >= BLOCK_8X8; + float simple_motion_features[NUM_SIMPLE_MOTION_FEATURES] = { 0.0f }; + int simple_motion_features_are_valid = 0; + if (try_prune_rect) { - simple_motion_search_prune_part( + av1_simple_motion_search_prune_part( cpi, x, pc_tree, mi_row, mi_col, bsize, &partition_none_allowed, &partition_horz_allowed, &partition_vert_allowed, &do_square_split, - &do_rectangular_split, &prune_horz, &prune_vert); + &do_rectangular_split, &prune_horz, &prune_vert, simple_motion_features, + &simple_motion_features_are_valid); } + // Max and min square partition levels are defined as the partition nodes that + // the recursive function rd_pick_partition() can reach. To implement this: + // only PARTITION_NONE is allowed if the current node equals min_sq_part, + // only PARTITION_SPLIT is allowed if the current node exceeds max_sq_part. + assert(block_size_wide[min_sq_part] == block_size_high[min_sq_part]); + assert(block_size_wide[max_sq_part] == block_size_high[max_sq_part]); + assert(min_sq_part <= max_sq_part); + assert(block_size_wide[bsize] == block_size_high[bsize]); + const int max_partition_size = block_size_wide[max_sq_part]; + const int min_partition_size = block_size_wide[min_sq_part]; + const int blksize = block_size_wide[bsize]; + assert(min_partition_size <= max_partition_size); + const int is_le_min_sq_part = blksize <= min_partition_size; + const int is_gt_max_sq_part = blksize > max_partition_size; + if (is_gt_max_sq_part) { + // If current block size is larger than max, only allow split. + partition_none_allowed = 0; + partition_horz_allowed = 0; + partition_vert_allowed = 0; + do_square_split = 1; + } else if (is_le_min_sq_part) { + // If current block size is less or equal to min, only allow none if valid + // block large enough; only allow split otherwise. + partition_horz_allowed = 0; + partition_vert_allowed = 0; + // only disable square split when current block is not at the picture + // boundary. otherwise, inherit the square split flag from previous logic + if (has_rows && has_cols) do_square_split = 0; + partition_none_allowed = !do_square_split; + } + do_square_split &= partition_cost[PARTITION_SPLIT] != INT_MAX; + BEGIN_PARTITION_SEARCH: if (x->must_find_valid_partition) { + do_square_split = + bsize_at_least_8x8 && partition_cost[PARTITION_SPLIT] != INT_MAX; partition_none_allowed = has_rows && has_cols; partition_horz_allowed = has_cols && yss <= xss && bsize_at_least_8x8 && cpi->oxcf.enable_rect_partitions; partition_vert_allowed = has_rows && xss <= yss && bsize_at_least_8x8 && cpi->oxcf.enable_rect_partitions; + terminate_partition_search = 0; } // Partition block source pixel variance. unsigned int pb_source_variance = UINT_MAX; + // Partition block sse after simple motion compensation, not in use now, + // but will be used for upcoming speed features + unsigned int pb_simple_motion_pred_sse = UINT_MAX; + (void)pb_simple_motion_pred_sse; + #if CONFIG_DIST_8X8 if (x->using_dist_8x8) { if (block_size_high[bsize] <= 8) partition_horz_allowed = 0; @@ -4078,8 +3384,9 @@ BEGIN_PARTITION_SEARCH: #endif // PARTITION_NONE - if (is_eq_min_sq_part) partition_none_allowed = 1; - if (partition_none_allowed && !is_gt_max_sq_part) { + if (is_le_min_sq_part && has_rows && has_cols) partition_none_allowed = 1; + if (!terminate_partition_search && partition_none_allowed && + !is_gt_max_sq_part) { int pt_cost = 0; if (bsize_at_least_8x8) { pt_cost = partition_cost[PARTITION_NONE] < INT_MAX @@ -4091,21 +3398,31 @@ BEGIN_PARTITION_SEARCH: (best_rdc.rdcost == INT64_MAX) ? INT64_MAX : (best_rdc.rdcost - partition_rd_cost); #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_remain_rdcost >= 0) { + if (best_remain_rdcost >= 0) { partition_attempts[PARTITION_NONE] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; + } +#endif + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, PARTITION_NONE, + bsize, ctx_none, best_remain_rdcost, 0); +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_NONE] += time; + partition_timer_on = 0; } #endif - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, - PARTITION_NONE, bsize, ctx_none, best_remain_rdcost); pb_source_variance = x->source_variance; + pb_simple_motion_pred_sse = x->simple_motion_pred_sse; if (none_rd) *none_rd = this_rdc.rdcost; cur_none_rd = this_rdc.rdcost; if (this_rdc.rate != INT_MAX) { if (cpi->sf.prune_ref_frame_for_rect_partitions) { const int ref_type = av1_ref_frame_type(ctx_none->mic.ref_frame); - for (int i = 0; i < 4; ++i) { - ref_frames_used[i] |= (1 << ref_type); - } + update_picked_ref_frames_mask(x, ref_type, bsize, + cm->seq_params.mib_size, mi_row, mi_col); } if (bsize_at_least_8x8) { this_rdc.rate += pt_cost; @@ -4125,25 +3442,6 @@ BEGIN_PARTITION_SEARCH: best_rdc = this_rdc; if (bsize_at_least_8x8) pc_tree->partitioning = PARTITION_NONE; -#if CONFIG_ONE_PASS_SVM - // Use ML if the block size is square and >= 16X16 - if (bsize >= BLOCK_16X16 && !frame_is_intra_only(cm) && - this_rdc.rate < INT_MAX && this_rdc.rate >= 0 && - !ctx_none->seg_feat) { - // Model Prediction - float score = 0.0f; - ml_op_svm_early_term(cpi, x, xd, ctx_none, &this_rdc, - pb_source_variance, bsize, &score); - - // Decide if we want to terminate early - if (score >= 0) { - do_square_split = 0; - do_rectangular_split = 0; - partition_horz_allowed = 0; - partition_vert_allowed = 0; - } - } -#endif if ((do_square_split || do_rectangular_split) && !x->e_mbd.lossless[xd->mi[0]->segment_id] && ctx_none->skippable) { const int use_ml_based_breakout = @@ -4169,51 +3467,17 @@ BEGIN_PARTITION_SEARCH: } } -#if CONFIG_FP_MB_STATS - // Check if every 16x16 first pass block statistics has zero - // motion and the corresponding first pass residue is small enough. - // If that is the case, check the difference variance between the - // current frame and the last frame. If the variance is small enough, - // stop further splitting in RD optimization - if (cpi->use_fp_mb_stats && do_square_split && - cm->base_qindex > qindex_skip_threshold_lookup[bsize]) { - int mb_row = mi_row >> 1; - int mb_col = mi_col >> 1; - int mb_row_end = - AOMMIN(mb_row + num_16x16_blocks_high_lookup[bsize], cm->mb_rows); - int mb_col_end = - AOMMIN(mb_col + num_16x16_blocks_wide_lookup[bsize], cm->mb_cols); - int r, c; - - int skip = 1; - for (r = mb_row; r < mb_row_end; r++) { - for (c = mb_col; c < mb_col_end; c++) { - const int mb_index = r * cm->mb_cols + c; - if (!(cpi->twopass.this_frame_mb_stats[mb_index] & - FPMB_MOTION_ZERO_MASK) || - !(cpi->twopass.this_frame_mb_stats[mb_index] & - FPMB_ERROR_SMALL_MASK)) { - skip = 0; - break; - } - } - if (skip == 0) { - break; - } - } - if (skip) { - if (src_diff_var == UINT_MAX) { - set_offsets(cpi, tile_info, x, mi_row, mi_col, bsize); - src_diff_var = get_sby_perpixel_diff_variance( - cpi, &x->plane[0].src, mi_row, mi_col, bsize); - } - if (src_diff_var < 8) { - do_square_split = 0; - do_rectangular_split = 0; - } - } + if (cpi->sf.simple_motion_search_early_term_none && cm->show_frame && + !frame_is_intra_only(cm) && bsize >= BLOCK_16X16 && + mi_row + mi_step < cm->mi_rows && mi_col + mi_step < cm->mi_cols && + this_rdc.rdcost < INT64_MAX && this_rdc.rdcost >= 0 && + this_rdc.rate < INT_MAX && this_rdc.rate >= 0 && + (do_square_split || do_rectangular_split)) { + av1_simple_motion_search_early_term_none( + cpi, x, pc_tree, mi_row, mi_col, bsize, &this_rdc, + &terminate_partition_search, simple_motion_features, + &simple_motion_features_are_valid); } -#endif } } @@ -4224,8 +3488,7 @@ BEGIN_PARTITION_SEARCH: if (cpi->sf.adaptive_motion_search) store_pred_mv(x, ctx_none); // PARTITION_SPLIT - if (is_eq_min_sq_part) do_square_split = 0; - if (do_square_split || is_gt_max_sq_part) { + if ((!terminate_partition_search && do_square_split) || is_gt_max_sq_part) { av1_init_rd_stats(&sum_rdc); subsize = get_partition_subsize(bsize, PARTITION_SPLIT); sum_rdc.rate = partition_cost[PARTITION_SPLIT]; @@ -4233,8 +3496,10 @@ BEGIN_PARTITION_SEARCH: int idx; #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_rdc.rdcost - sum_rdc.rdcost >= 0) { + if (best_rdc.rdcost - sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_SPLIT] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } #endif for (idx = 0; idx < 4 && sum_rdc.rdcost < best_rdc.rdcost; ++idx) { @@ -4251,8 +3516,6 @@ BEGIN_PARTITION_SEARCH: const int64_t best_remain_rdcost = best_rdc.rdcost == INT64_MAX ? INT64_MAX : (best_rdc.rdcost - sum_rdc.rdcost); - if (cpi->sf.prune_ref_frame_for_rect_partitions) - pc_tree->split[idx]->none.rate = INT_MAX; rd_pick_partition(cpi, td, tile_data, tp, mi_row + y_idx, mi_col + x_idx, subsize, max_sq_part, min_sq_part, &this_rdc, best_remain_rdcost, pc_tree->split[idx], p_split_rd); @@ -4264,16 +3527,6 @@ BEGIN_PARTITION_SEARCH: sum_rdc.rate += this_rdc.rate; sum_rdc.dist += this_rdc.dist; sum_rdc.rdcost += this_rdc.rdcost; - if (cpi->sf.prune_ref_frame_for_rect_partitions && - pc_tree->split[idx]->none.rate != INT_MAX) { - const int ref_type = - av1_ref_frame_type(pc_tree->split[idx]->none.mic.ref_frame); - ref_frames_used[idx] |= (1 << ref_type); - - if (cpi->sf.prune_ref_mode_for_partitions) { - split_mbmi[idx] = &pc_tree->split[idx]->none.mic; - } - } if (idx <= 1 && (bsize <= BLOCK_8X8 || pc_tree->split[idx]->partitioning == PARTITION_NONE)) { const MB_MODE_INFO *const mbmi = &pc_tree->split[idx]->none.mic; @@ -4285,6 +3538,14 @@ BEGIN_PARTITION_SEARCH: } } } +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_SPLIT] += time; + partition_timer_on = 0; + } +#endif const int reached_last_index = (idx == 4); if (reached_last_index && sum_rdc.rdcost < best_rdc.rdcost) { @@ -4304,96 +3565,6 @@ BEGIN_PARTITION_SEARCH: restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } // if (do_split) - pc_tree->horizontal[0].skip_ref_frame_mask = 0; - pc_tree->horizontal[1].skip_ref_frame_mask = 0; - pc_tree->vertical[0].skip_ref_frame_mask = 0; - pc_tree->vertical[1].skip_ref_frame_mask = 0; - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - int used_frames; - used_frames = ref_frames_used[0] | ref_frames_used[1]; - if (used_frames) pc_tree->horizontal[0].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[2] | ref_frames_used[3]; - if (used_frames) pc_tree->horizontal[1].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[0] | ref_frames_used[2]; - if (used_frames) pc_tree->vertical[0].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[1] | ref_frames_used[3]; - if (used_frames) pc_tree->vertical[1].skip_ref_frame_mask = ~used_frames; - } - - for (int i = 0; i < 2; ++i) { - pc_tree->horizontal[i].ref_selected[0] = - pc_tree->horizontal[i].ref_selected[1] = NONE_FRAME; - pc_tree->horizontal[i].mode_selected = -1; - pc_tree->vertical[i].ref_selected[0] = - pc_tree->vertical[i].ref_selected[1] = NONE_FRAME; - pc_tree->vertical[i].mode_selected = -1; - } - - if (cpi->sf.prune_ref_mode_for_partitions) { - // horizontal partition - for (int idx = 0; idx < 4; idx += 2) { - const int horz_idx = idx / 2; - if (split_mbmi[idx] && split_mbmi[idx + 1] && - split_mbmi[idx]->ref_frame[0] > INTRA_FRAME) { - if (!has_second_ref(split_mbmi[idx])) { - // Single ref - if (split_mbmi[idx]->ref_frame[0] == - split_mbmi[idx + 1]->ref_frame[0] && - !has_second_ref(split_mbmi[idx + 1])) { - const int ref_type = av1_ref_frame_type(split_mbmi[idx]->ref_frame); - // Overwrite skip_ref_frame_mask for the current block - const int used_frames = (1 << ref_type); - pc_tree->horizontal[horz_idx].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontal[horz_idx].ref_selected[0] = - split_mbmi[idx]->ref_frame[0]; -#if 0 - // TODO(zoeliu@gmail.com): To consider the scenario of obmc - if (split_mbmi[idx]->motion_mode == - split_mbmi[idx + 1]->motion_mode && - split_mbmi[idx]->motion_mode == SIMPLE_TRANSLATION && - split_mbmi[idx]->use_wedge_interintra == 0) { - pc_tree->horizontal[horz_idx].mode_selected = SIMPLE_TRANSLATION; - } -#endif // 0 - } - } else { - // TODO(zoeliu@gmail.com): To handle comp ref - } - } - } - // vertical partition - for (int idx = 0; idx < 2; ++idx) { - const int vert_idx = idx; - if (split_mbmi[idx] && split_mbmi[idx + 2] && - split_mbmi[idx]->ref_frame[0] > INTRA_FRAME) { - if (!has_second_ref(split_mbmi[idx])) { - // Single ref - if (split_mbmi[idx]->ref_frame[0] == - split_mbmi[idx + 2]->ref_frame[0] && - !has_second_ref(split_mbmi[idx + 2])) { - const int ref_type = av1_ref_frame_type(split_mbmi[idx]->ref_frame); - // Overwrite skip_ref_frame_mask for the current block - const int used_frames = (1 << ref_type); - pc_tree->vertical[vert_idx].skip_ref_frame_mask = ~used_frames; - pc_tree->vertical[vert_idx].ref_selected[0] = - split_mbmi[idx]->ref_frame[0]; -#if 0 - // TODO(zoeliu@gmail.com): To consider the scenario of obmc - if (split_mbmi[idx]->motion_mode == - split_mbmi[idx + 2]->motion_mode && - split_mbmi[idx]->motion_mode == SIMPLE_TRANSLATION && - split_mbmi[idx]->use_wedge_interintra == 0) { - pc_tree->vertical[vert_idx].mode_selected = SIMPLE_TRANSLATION; - } -#endif // 0 - } - } else { - // TODO(zoeliu@gmail.com): To handle comp ref - } - } - } - } - if (cpi->sf.ml_prune_rect_partition && !frame_is_intra_only(cm) && (partition_horz_allowed || partition_vert_allowed) && !(prune_horz || prune_vert)) { @@ -4404,7 +3575,7 @@ BEGIN_PARTITION_SEARCH: // PARTITION_HORZ assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !partition_horz_allowed)); - if (partition_horz_allowed && !prune_horz && + if (!terminate_partition_search && partition_horz_allowed && !prune_horz && (do_rectangular_split || active_h_edge(cpi, mi_row, mi_step)) && !is_gt_max_sq_part) { av1_init_rd_stats(&sum_rdc); @@ -4421,13 +3592,14 @@ BEGIN_PARTITION_SEARCH: ? INT64_MAX : (best_rdc.rdcost - sum_rdc.rdcost); #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_remain_rdcost >= 0) { + if (best_remain_rdcost >= 0) { partition_attempts[PARTITION_HORZ] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } #endif - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, - PARTITION_HORZ, subsize, &pc_tree->horizontal[0], - best_remain_rdcost); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, PARTITION_HORZ, + subsize, &pc_tree->horizontal[0], best_remain_rdcost, 0); if (this_rdc.rate == INT_MAX) { sum_rdc.rdcost = INT64_MAX; @@ -4457,9 +3629,9 @@ BEGIN_PARTITION_SEARCH: pc_tree->horizontal[1].pred_interp_filter = av1_extract_interp_filter(ctx_h->mic.interp_filters, 0); } - rd_pick_sb_modes(cpi, tile_data, x, mi_row + mi_step, mi_col, &this_rdc, - PARTITION_HORZ, subsize, &pc_tree->horizontal[1], - best_rdc.rdcost - sum_rdc.rdcost); + pick_sb_modes(cpi, tile_data, x, mi_row + mi_step, mi_col, &this_rdc, + PARTITION_HORZ, subsize, &pc_tree->horizontal[1], + best_rdc.rdcost - sum_rdc.rdcost, 0); horz_rd[1] = this_rdc.rdcost; if (this_rdc.rate == INT_MAX) { @@ -4470,6 +3642,14 @@ BEGIN_PARTITION_SEARCH: sum_rdc.rdcost += this_rdc.rdcost; } } +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_HORZ] += time; + partition_timer_on = 0; + } +#endif if (sum_rdc.rdcost < best_rdc.rdcost) { sum_rdc.rdcost = RDCOST(x->rdmult, sum_rdc.rate, sum_rdc.dist); @@ -4484,7 +3664,7 @@ BEGIN_PARTITION_SEARCH: // PARTITION_VERT assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !partition_vert_allowed)); - if (partition_vert_allowed && !prune_vert && + if (!terminate_partition_search && partition_vert_allowed && !prune_vert && (do_rectangular_split || active_v_edge(cpi, mi_col, mi_step)) && !is_gt_max_sq_part) { av1_init_rd_stats(&sum_rdc); @@ -4503,13 +3683,14 @@ BEGIN_PARTITION_SEARCH: ? INT64_MAX : (best_rdc.rdcost - sum_rdc.rdcost); #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_remain_rdcost >= 0) { + if (best_remain_rdcost >= 0) { partition_attempts[PARTITION_VERT] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } #endif - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, - PARTITION_VERT, subsize, &pc_tree->vertical[0], - best_remain_rdcost); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &this_rdc, PARTITION_VERT, + subsize, &pc_tree->vertical[0], best_remain_rdcost, 0); if (this_rdc.rate == INT_MAX) { sum_rdc.rdcost = INT64_MAX; @@ -4538,9 +3719,9 @@ BEGIN_PARTITION_SEARCH: pc_tree->vertical[1].pred_interp_filter = av1_extract_interp_filter(ctx_none->mic.interp_filters, 0); } - rd_pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + mi_step, &this_rdc, - PARTITION_VERT, subsize, &pc_tree->vertical[1], - best_rdc.rdcost - sum_rdc.rdcost); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + mi_step, &this_rdc, + PARTITION_VERT, subsize, &pc_tree->vertical[1], + best_rdc.rdcost - sum_rdc.rdcost, 0); vert_rd[1] = this_rdc.rdcost; if (this_rdc.rate == INT_MAX) { @@ -4551,6 +3732,14 @@ BEGIN_PARTITION_SEARCH: sum_rdc.rdcost += this_rdc.rdcost; } } +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_VERT] += time; + partition_timer_on = 0; + } +#endif if (sum_rdc.rdcost < best_rdc.rdcost) { sum_rdc.rdcost = RDCOST(x->rdmult, sum_rdc.rate, sum_rdc.dist); @@ -4574,6 +3763,15 @@ BEGIN_PARTITION_SEARCH: } } + if (use_pb_simple_motion_pred_sse(cpi) && + pb_simple_motion_pred_sse == UINT_MAX) { + const MV ref_mv_full = { .row = 0, .col = 0 }; + unsigned int var = 0; + + av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, ref_mv_full, 0, + &pb_simple_motion_pred_sse, &var); + } + assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !do_rectangular_split)); const int ext_partition_allowed = @@ -4581,8 +3779,10 @@ BEGIN_PARTITION_SEARCH: // The standard AB partitions are allowed whenever ext-partition-types are // allowed - int horzab_partition_allowed = ext_partition_allowed; - int vertab_partition_allowed = ext_partition_allowed; + int horzab_partition_allowed = + ext_partition_allowed & cpi->oxcf.enable_ab_partitions; + int vertab_partition_allowed = + ext_partition_allowed & cpi->oxcf.enable_ab_partitions; #if CONFIG_DIST_8X8 if (x->using_dist_8x8) { @@ -4668,8 +3868,14 @@ BEGIN_PARTITION_SEARCH: &verta_partition_allowed, &vertb_partition_allowed); } + horza_partition_allowed &= cpi->oxcf.enable_ab_partitions; + horzb_partition_allowed &= cpi->oxcf.enable_ab_partitions; + verta_partition_allowed &= cpi->oxcf.enable_ab_partitions; + vertb_partition_allowed &= cpi->oxcf.enable_ab_partitions; + // PARTITION_HORZ_A - if (partition_horz_allowed && horza_partition_allowed && !is_gt_max_sq_part) { + if (!terminate_partition_search && partition_horz_allowed && + horza_partition_allowed && !is_gt_max_sq_part) { subsize = get_partition_subsize(bsize, PARTITION_HORZ_A); pc_tree->horizontala[0].rd_mode_is_ready = 0; pc_tree->horizontala[1].rd_mode_is_ready = 0; @@ -4685,56 +3891,16 @@ BEGIN_PARTITION_SEARCH: pc_tree->horizontala[1].rd_mode_is_ready = 1; } } - for (int i = 0; i < 3; ++i) { - pc_tree->horizontala[i].skip_ref_frame_mask = 0; - pc_tree->horizontala[i].ref_selected[0] = - pc_tree->horizontala[i].ref_selected[1] = NONE_FRAME; - } - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - int used_frames; - used_frames = ref_frames_used[0]; - if (used_frames) - pc_tree->horizontala[0].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[1]; - if (used_frames) - pc_tree->horizontala[1].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[2] | ref_frames_used[3]; - if (used_frames) - pc_tree->horizontala[2].skip_ref_frame_mask = ~used_frames; - } - if (cpi->sf.prune_ref_mode_for_partitions) { - // Overwrite skip_ref_frame_mask for the current block - if (split_mbmi[0] && split_mbmi[0]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[0])) { // single ref - const int used_frames = 1 << (int)split_mbmi[0]->ref_frame[0]; - pc_tree->horizontala[0].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontala[0].ref_selected[0] = split_mbmi[0]->ref_frame[0]; - } - if (split_mbmi[1] && split_mbmi[1]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[1])) { // single ref - const int used_frames = 1 << (int)split_mbmi[1]->ref_frame[0]; - pc_tree->horizontala[1].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontala[1].ref_selected[0] = split_mbmi[1]->ref_frame[0]; - } - if (split_mbmi[2] && split_mbmi[3] && - split_mbmi[2]->ref_frame[0] > INTRA_FRAME && - split_mbmi[2]->ref_frame[0] == split_mbmi[3]->ref_frame[0] && - !has_second_ref(split_mbmi[2]) && - !has_second_ref(split_mbmi[3])) { // single ref - const int used_frames = 1 << (int)split_mbmi[2]->ref_frame[0]; - pc_tree->horizontala[2].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontala[2].ref_selected[0] = split_mbmi[2]->ref_frame[0]; - } - } #if CONFIG_COLLECT_PARTITION_STATS { RD_STATS tmp_sum_rdc; av1_init_rd_stats(&tmp_sum_rdc); tmp_sum_rdc.rate = x->partition_cost[pl][PARTITION_HORZ_A]; tmp_sum_rdc.rdcost = RDCOST(x->rdmult, tmp_sum_rdc.rate, 0); - if (!frame_is_intra_only(cm) && - best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { + if (best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_HORZ_A] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } } #endif @@ -4743,10 +3909,19 @@ BEGIN_PARTITION_SEARCH: PARTITION_HORZ_A, mi_row, mi_col, bsize2, mi_row, mi_col + mi_step, bsize2, mi_row + mi_step, mi_col, subsize); +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_HORZ_A] += time; + partition_timer_on = 0; + } +#endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } // PARTITION_HORZ_B - if (partition_horz_allowed && horzb_partition_allowed && !is_gt_max_sq_part) { + if (!terminate_partition_search && partition_horz_allowed && + horzb_partition_allowed && !is_gt_max_sq_part) { subsize = get_partition_subsize(bsize, PARTITION_HORZ_B); pc_tree->horizontalb[0].rd_mode_is_ready = 0; pc_tree->horizontalb[1].rd_mode_is_ready = 0; @@ -4756,56 +3931,16 @@ BEGIN_PARTITION_SEARCH: pc_tree->horizontalb[0].mic.partition = PARTITION_HORZ_B; pc_tree->horizontalb[0].rd_mode_is_ready = 1; } - for (int i = 0; i < 3; ++i) { - pc_tree->horizontalb[i].skip_ref_frame_mask = 0; - pc_tree->horizontalb[i].ref_selected[0] = - pc_tree->horizontalb[i].ref_selected[1] = NONE_FRAME; - } - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - int used_frames; - used_frames = ref_frames_used[0] | ref_frames_used[1]; - if (used_frames) - pc_tree->horizontalb[0].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[2]; - if (used_frames) - pc_tree->horizontalb[1].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[3]; - if (used_frames) - pc_tree->horizontalb[2].skip_ref_frame_mask = ~used_frames; - } - if (cpi->sf.prune_ref_mode_for_partitions) { - // Overwrite skip_ref_frame_mask for the current block - if (split_mbmi[0] && split_mbmi[1] && - split_mbmi[0]->ref_frame[0] > INTRA_FRAME && - split_mbmi[0]->ref_frame[0] == split_mbmi[1]->ref_frame[0] && - !has_second_ref(split_mbmi[0]) && - !has_second_ref(split_mbmi[1])) { // single ref - const int used_frames = 1 << (int)split_mbmi[0]->ref_frame[0]; - pc_tree->horizontalb[0].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontalb[0].ref_selected[0] = split_mbmi[0]->ref_frame[0]; - } - if (split_mbmi[2] && split_mbmi[2]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[2])) { // single ref - const int used_frames = 1 << (int)split_mbmi[2]->ref_frame[0]; - pc_tree->horizontalb[1].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontalb[1].ref_selected[0] = split_mbmi[2]->ref_frame[0]; - } - if (split_mbmi[3] && split_mbmi[3]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[3])) { // single ref - const int used_frames = 1 << (int)split_mbmi[3]->ref_frame[0]; - pc_tree->horizontalb[2].skip_ref_frame_mask = ~used_frames; - pc_tree->horizontalb[2].ref_selected[0] = split_mbmi[3]->ref_frame[0]; - } - } #if CONFIG_COLLECT_PARTITION_STATS { RD_STATS tmp_sum_rdc; av1_init_rd_stats(&tmp_sum_rdc); tmp_sum_rdc.rate = x->partition_cost[pl][PARTITION_HORZ_B]; tmp_sum_rdc.rdcost = RDCOST(x->rdmult, tmp_sum_rdc.rate, 0); - if (!frame_is_intra_only(cm) && - best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { + if (best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_HORZ_B] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } } #endif @@ -4814,11 +3949,21 @@ BEGIN_PARTITION_SEARCH: PARTITION_HORZ_B, mi_row, mi_col, subsize, mi_row + mi_step, mi_col, bsize2, mi_row + mi_step, mi_col + mi_step, bsize2); + +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_HORZ_B] += time; + partition_timer_on = 0; + } +#endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } // PARTITION_VERT_A - if (partition_vert_allowed && verta_partition_allowed && !is_gt_max_sq_part) { + if (!terminate_partition_search && partition_vert_allowed && + verta_partition_allowed && !is_gt_max_sq_part) { subsize = get_partition_subsize(bsize, PARTITION_VERT_A); pc_tree->verticala[0].rd_mode_is_ready = 0; pc_tree->verticala[1].rd_mode_is_ready = 0; @@ -4828,53 +3973,16 @@ BEGIN_PARTITION_SEARCH: pc_tree->verticala[0].mic.partition = PARTITION_VERT_A; pc_tree->verticala[0].rd_mode_is_ready = 1; } - for (int i = 0; i < 3; ++i) { - pc_tree->verticala[i].skip_ref_frame_mask = 0; - pc_tree->verticala[i].ref_selected[0] = - pc_tree->verticala[i].ref_selected[1] = NONE_FRAME; - } - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - int used_frames; - used_frames = ref_frames_used[0]; - if (used_frames) pc_tree->verticala[0].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[2]; - if (used_frames) pc_tree->verticala[1].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[1] | ref_frames_used[3]; - if (used_frames) pc_tree->verticala[2].skip_ref_frame_mask = ~used_frames; - } - if (cpi->sf.prune_ref_mode_for_partitions) { - // Overwrite skip_ref_frame_mask for the current block - if (split_mbmi[0] && split_mbmi[0]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[0])) { // single ref - const int used_frames = 1 << (int)split_mbmi[0]->ref_frame[0]; - pc_tree->verticala[0].skip_ref_frame_mask = ~used_frames; - pc_tree->verticala[0].ref_selected[0] = split_mbmi[0]->ref_frame[0]; - } - if (split_mbmi[2] && split_mbmi[2]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[2])) { // single ref - const int used_frames = 1 << (int)split_mbmi[2]->ref_frame[0]; - pc_tree->verticala[1].skip_ref_frame_mask = ~used_frames; - pc_tree->verticala[1].ref_selected[0] = split_mbmi[2]->ref_frame[0]; - } - if (split_mbmi[1] && split_mbmi[3] && - split_mbmi[1]->ref_frame[0] > INTRA_FRAME && - split_mbmi[1]->ref_frame[0] == split_mbmi[3]->ref_frame[0] && - !has_second_ref(split_mbmi[1]) && - !has_second_ref(split_mbmi[3])) { // single ref - const int used_frames = 1 << (int)split_mbmi[1]->ref_frame[0]; - pc_tree->verticala[2].skip_ref_frame_mask = ~used_frames; - pc_tree->verticala[2].ref_selected[0] = split_mbmi[1]->ref_frame[0]; - } - } #if CONFIG_COLLECT_PARTITION_STATS { RD_STATS tmp_sum_rdc; av1_init_rd_stats(&tmp_sum_rdc); tmp_sum_rdc.rate = x->partition_cost[pl][PARTITION_VERT_A]; tmp_sum_rdc.rdcost = RDCOST(x->rdmult, tmp_sum_rdc.rate, 0); - if (!frame_is_intra_only(cm) && - best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { + if (best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_VERT_A] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } } #endif @@ -4883,10 +3991,19 @@ BEGIN_PARTITION_SEARCH: PARTITION_VERT_A, mi_row, mi_col, bsize2, mi_row + mi_step, mi_col, bsize2, mi_row, mi_col + mi_step, subsize); +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_VERT_A] += time; + partition_timer_on = 0; + } +#endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } // PARTITION_VERT_B - if (partition_vert_allowed && vertb_partition_allowed && !is_gt_max_sq_part) { + if (!terminate_partition_search && partition_vert_allowed && + vertb_partition_allowed && !is_gt_max_sq_part) { subsize = get_partition_subsize(bsize, PARTITION_VERT_B); pc_tree->verticalb[0].rd_mode_is_ready = 0; pc_tree->verticalb[1].rd_mode_is_ready = 0; @@ -4896,44 +4013,6 @@ BEGIN_PARTITION_SEARCH: pc_tree->verticalb[0].mic.partition = PARTITION_VERT_B; pc_tree->verticalb[0].rd_mode_is_ready = 1; } - for (int i = 0; i < 3; ++i) { - pc_tree->verticalb[i].skip_ref_frame_mask = 0; - pc_tree->verticalb[i].ref_selected[0] = - pc_tree->verticalb[i].ref_selected[1] = NONE_FRAME; - } - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - int used_frames; - used_frames = ref_frames_used[0] | ref_frames_used[2]; - if (used_frames) pc_tree->verticalb[0].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[1]; - if (used_frames) pc_tree->verticalb[1].skip_ref_frame_mask = ~used_frames; - used_frames = ref_frames_used[3]; - if (used_frames) pc_tree->verticalb[2].skip_ref_frame_mask = ~used_frames; - } - if (cpi->sf.prune_ref_mode_for_partitions) { - // Overwrite skip_ref_frame_mask for the current block - if (split_mbmi[0] && split_mbmi[2] && - split_mbmi[0]->ref_frame[0] > INTRA_FRAME && - split_mbmi[0]->ref_frame[0] == split_mbmi[2]->ref_frame[0] && - !has_second_ref(split_mbmi[0]) && - !has_second_ref(split_mbmi[2])) { // single ref - const int used_frames = 1 << (int)split_mbmi[0]->ref_frame[0]; - pc_tree->verticalb[0].skip_ref_frame_mask = ~used_frames; - pc_tree->verticalb[0].ref_selected[0] = split_mbmi[0]->ref_frame[0]; - } - if (split_mbmi[1] && split_mbmi[1]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[1])) { // single ref - const int used_frames = 1 << (int)split_mbmi[1]->ref_frame[0]; - pc_tree->verticalb[1].skip_ref_frame_mask = ~used_frames; - pc_tree->verticalb[1].ref_selected[0] = split_mbmi[1]->ref_frame[0]; - } - if (split_mbmi[3] && split_mbmi[3]->ref_frame[0] > INTRA_FRAME && - !has_second_ref(split_mbmi[3])) { // single ref - const int used_frames = 1 << (int)split_mbmi[3]->ref_frame[0]; - pc_tree->verticalb[2].skip_ref_frame_mask = ~used_frames; - pc_tree->verticalb[2].ref_selected[0] = split_mbmi[3]->ref_frame[0]; - } - } #if CONFIG_COLLECT_PARTITION_STATS { RD_STATS tmp_sum_rdc; @@ -4943,6 +4022,8 @@ BEGIN_PARTITION_SEARCH: if (!frame_is_intra_only(cm) && best_rdc.rdcost - tmp_sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_VERT_B] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } } #endif @@ -4951,6 +4032,14 @@ BEGIN_PARTITION_SEARCH: PARTITION_VERT_B, mi_row, mi_col, subsize, mi_row, mi_col + mi_step, bsize2, mi_row + mi_step, mi_col + mi_step, bsize2); +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_VERT_B] += time; + partition_timer_on = 0; + } +#endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } @@ -4958,8 +4047,10 @@ BEGIN_PARTITION_SEARCH: // PARTITION_VERT_4 for this block. This is almost the same as // ext_partition_allowed, except that we don't allow 128x32 or 32x128 // blocks, so we require that bsize is not BLOCK_128X128. - const int partition4_allowed = - ext_partition_allowed && bsize != BLOCK_128X128; + const int partition4_allowed = cpi->oxcf.enable_1to4_partitions && + ext_partition_allowed && + bsize != BLOCK_128X128; + int partition_horz4_allowed = partition4_allowed && partition_horz_allowed; int partition_vert4_allowed = partition4_allowed && partition_vert_allowed; if (cpi->sf.prune_ext_partition_types_search_level == 2) { @@ -4991,9 +4082,14 @@ BEGIN_PARTITION_SEARCH: } #endif + if (blksize < (min_partition_size << 2)) { + partition_horz4_allowed = 0; + partition_vert4_allowed = 0; + } + // PARTITION_HORZ_4 assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !partition_horz4_allowed)); - if (partition_horz4_allowed && has_rows && + if (!terminate_partition_search && partition_horz4_allowed && has_rows && (do_rectangular_split || active_h_edge(cpi, mi_row, mi_step)) && !is_gt_max_sq_part) { av1_init_rd_stats(&sum_rdc); @@ -5005,8 +4101,10 @@ BEGIN_PARTITION_SEARCH: sum_rdc.rdcost = RDCOST(x->rdmult, sum_rdc.rate, 0); #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_rdc.rdcost - sum_rdc.rdcost >= 0) { + if (best_rdc.rdcost - sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_HORZ_4] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } #endif for (int i = 0; i < 4; ++i) { @@ -5017,13 +4115,6 @@ BEGIN_PARTITION_SEARCH: PICK_MODE_CONTEXT *ctx_this = &pc_tree->horizontal4[i]; ctx_this->rd_mode_is_ready = 0; - ctx_this->skip_ref_frame_mask = 0; - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - const int used_frames = i <= 1 - ? (ref_frames_used[0] | ref_frames_used[1]) - : (ref_frames_used[2] | ref_frames_used[3]); - if (used_frames) ctx_this->skip_ref_frame_mask = ~used_frames; - } if (!rd_try_subblock(cpi, td, tile_data, tp, (i == 3), this_mi_row, mi_col, subsize, &best_rdc, &sum_rdc, &this_rdc, PARTITION_HORZ_4, ctx_prev, ctx_this)) @@ -5039,12 +4130,21 @@ BEGIN_PARTITION_SEARCH: pc_tree->partitioning = PARTITION_HORZ_4; } } + +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_HORZ_4] += time; + partition_timer_on = 0; + } +#endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } // PARTITION_VERT_4 assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !partition_vert4_allowed)); - if (partition_vert4_allowed && has_cols && + if (!terminate_partition_search && partition_vert4_allowed && has_cols && (do_rectangular_split || active_v_edge(cpi, mi_row, mi_step)) && !is_gt_max_sq_part) { av1_init_rd_stats(&sum_rdc); @@ -5056,8 +4156,10 @@ BEGIN_PARTITION_SEARCH: sum_rdc.rdcost = RDCOST(x->rdmult, sum_rdc.rate, 0); #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_rdc.rdcost - sum_rdc.rdcost >= 0) { + if (best_rdc.rdcost - sum_rdc.rdcost >= 0) { partition_attempts[PARTITION_VERT_4] += 1; + aom_usec_timer_start(&partition_timer); + partition_timer_on = 1; } #endif for (int i = 0; i < 4; ++i) { @@ -5068,13 +4170,6 @@ BEGIN_PARTITION_SEARCH: PICK_MODE_CONTEXT *ctx_this = &pc_tree->vertical4[i]; ctx_this->rd_mode_is_ready = 0; - ctx_this->skip_ref_frame_mask = 0; - if (cpi->sf.prune_ref_frame_for_rect_partitions) { - const int used_frames = i <= 1 - ? (ref_frames_used[0] | ref_frames_used[2]) - : (ref_frames_used[1] | ref_frames_used[3]); - if (used_frames) ctx_this->skip_ref_frame_mask = ~used_frames; - } if (!rd_try_subblock(cpi, td, tile_data, tp, (i == 3), mi_row, this_mi_col, subsize, &best_rdc, &sum_rdc, &this_rdc, PARTITION_VERT_4, ctx_prev, ctx_this)) @@ -5090,6 +4185,14 @@ BEGIN_PARTITION_SEARCH: pc_tree->partitioning = PARTITION_VERT_4; } } +#if CONFIG_COLLECT_PARTITION_STATS + if (partition_timer_on) { + aom_usec_timer_mark(&partition_timer); + int64_t time = aom_usec_timer_elapsed(&partition_timer); + partition_times[PARTITION_VERT_4] += time; + partition_timer_on = 0; + } +#endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } @@ -5097,10 +4200,8 @@ BEGIN_PARTITION_SEARCH: // Did not find a valid partition, go back and search again, with less // constraint on which partition types to search. x->must_find_valid_partition = 1; -#if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm)) { - part_stats->partition_redo += 1; - } +#if CONFIG_COLLECT_PARTITION_STATS == 2 + part_stats->partition_redo += 1; #endif goto BEGIN_PARTITION_SEARCH; } @@ -5113,12 +4214,43 @@ BEGIN_PARTITION_SEARCH: *rd_cost = best_rdc; #if CONFIG_COLLECT_PARTITION_STATS - if (!frame_is_intra_only(cm) && best_rdc.rate < INT_MAX && - best_rdc.dist < INT64_MAX) { + if (best_rdc.rate < INT_MAX && best_rdc.dist < INT64_MAX) { partition_decisions[pc_tree->partitioning] += 1; } #endif +#if CONFIG_COLLECT_PARTITION_STATS == 1 + // If CONFIG_COLLECT_PARTITION_STATS is 1, then print out the stats for each + // prediction block + FILE *f = fopen("data.csv", "a"); + fprintf(f, "%d,%d,%d,", bsize, cm->show_frame, frame_is_intra_only(cm)); + for (int idx = 0; idx < EXT_PARTITION_TYPES; idx++) { + fprintf(f, "%d,", partition_decisions[idx]); + } + for (int idx = 0; idx < EXT_PARTITION_TYPES; idx++) { + fprintf(f, "%d,", partition_attempts[idx]); + } + for (int idx = 0; idx < EXT_PARTITION_TYPES; idx++) { + fprintf(f, "%ld,", partition_times[idx]); + } + fprintf(f, "\n"); + fclose(f); +#endif + +#if CONFIG_COLLECT_PARTITION_STATS == 2 + // If CONFIG_COLLECTION_PARTITION_STATS is 2, then we print out the stats for + // the whole clip. So we need to pass the information upstream to the encoder + const int bsize_idx = av1_get_bsize_idx_for_part_stats(bsize); + int *agg_attempts = part_stats->partition_attempts[bsize_idx]; + int *agg_decisions = part_stats->partition_decisions[bsize_idx]; + int64_t *agg_times = part_stats->partition_times[bsize_idx]; + for (int idx = 0; idx < EXT_PARTITION_TYPES; idx++) { + agg_attempts[idx] += partition_attempts[idx]; + agg_decisions[idx] += partition_decisions[idx]; + agg_times[idx] += partition_times[idx]; + } +#endif + if (best_rdc.rate < INT_MAX && best_rdc.dist < INT64_MAX && pc_tree->index != 3) { if (bsize == cm->seq_params.sb_size) { @@ -5138,19 +4270,23 @@ BEGIN_PARTITION_SEARCH: assert(tp_orig == *tp); } } +#undef NUM_SIMPLE_MOTION_FEATURES // Set all the counters as max. static void init_first_partition_pass_stats_tables( - FIRST_PARTITION_PASS_STATS *stats) { + AV1_COMP *cpi, FIRST_PARTITION_PASS_STATS *stats) { for (int i = 0; i < FIRST_PARTITION_PASS_STATS_TABLES; ++i) { memset(stats[i].ref0_counts, 0xff, sizeof(stats[i].ref0_counts)); memset(stats[i].ref1_counts, 0xff, sizeof(stats[i].ref1_counts)); stats[i].sample_counts = INT_MAX; + if (cpi->sf.use_first_partition_pass_interintra_stats) + memset(stats[i].interintra_motion_mode_count, 0xff, + sizeof(stats[i].interintra_motion_mode_count)); } } -// Minimum number of samples to trigger the -// mode_pruning_based_on_two_pass_partition_search feature. +// Minimum number of samples to trigger the mode pruning in +// two_pass_partition_search feature. #define FIRST_PARTITION_PASS_MIN_SAMPLES 16 static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, @@ -5165,7 +4301,6 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int row, col; int dr = 0; - int count = 0; double r0, rk, beta; if (tpl_frame->is_valid == 0) return orig_rdmult; @@ -5182,8 +4317,6 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, intra_cost += this_stats->intra_cost; mc_dep_cost += this_stats->mc_dep_cost; - - ++count; } } @@ -5273,8 +4406,7 @@ static void first_partition_search_pass(AV1_COMP *cpi, ThreadData *td, const SPEED_FEATURES *const sf = &cpi->sf; // Reset the stats tables. - if (sf->mode_pruning_based_on_two_pass_partition_search) - av1_zero(x->first_partition_pass_stats); + av1_zero(x->first_partition_pass_stats); AV1_COMMON *const cm = &cpi->common; const BLOCK_SIZE sb_size = cm->seq_params.sb_size; @@ -5286,6 +4418,7 @@ static void first_partition_search_pass(AV1_COMP *cpi, ThreadData *td, x->cb_partition_scan = 0; x->source_variance = UINT_MAX; + x->simple_motion_pred_sse = UINT_MAX; if (sf->adaptive_pred_interp_filter) { const int leaf_nodes = 256; for (int i = 0; i < leaf_nodes; ++i) { @@ -5314,39 +4447,30 @@ static void first_partition_search_pass(AV1_COMP *cpi, ThreadData *td, x->use_cb_search_range = 1; - if (sf->mode_pruning_based_on_two_pass_partition_search) { - for (int i = 0; i < FIRST_PARTITION_PASS_STATS_TABLES; ++i) { - FIRST_PARTITION_PASS_STATS *const stat = - &x->first_partition_pass_stats[i]; - if (stat->sample_counts < FIRST_PARTITION_PASS_MIN_SAMPLES) { - // If there are not enough samples collected, make all available. - memset(stat->ref0_counts, 0xff, sizeof(stat->ref0_counts)); - memset(stat->ref1_counts, 0xff, sizeof(stat->ref1_counts)); - } else if (sf->selective_ref_frame < 3) { - // ALTREF2_FRAME and BWDREF_FRAME may be skipped during the - // initial partition scan, so we don't eliminate them. - stat->ref0_counts[ALTREF2_FRAME] = 0xff; - stat->ref1_counts[ALTREF2_FRAME] = 0xff; - stat->ref0_counts[BWDREF_FRAME] = 0xff; - stat->ref1_counts[BWDREF_FRAME] = 0xff; + for (int i = 0; i < FIRST_PARTITION_PASS_STATS_TABLES; ++i) { + FIRST_PARTITION_PASS_STATS *const stat = &x->first_partition_pass_stats[i]; + if (stat->sample_counts < FIRST_PARTITION_PASS_MIN_SAMPLES) { + // If there are not enough samples collected, make all available. + memset(stat->ref0_counts, 0xff, sizeof(stat->ref0_counts)); + memset(stat->ref1_counts, 0xff, sizeof(stat->ref1_counts)); + if (cpi->sf.use_first_partition_pass_interintra_stats) + memset(stat->interintra_motion_mode_count, 0xff, + sizeof(stat->interintra_motion_mode_count)); + } else if (sf->selective_ref_frame < 3) { + // ALTREF2_FRAME and BWDREF_FRAME may be skipped during the + // initial partition scan, so we don't eliminate them. + stat->ref0_counts[ALTREF2_FRAME] = 0xff; + stat->ref1_counts[ALTREF2_FRAME] = 0xff; + stat->ref0_counts[BWDREF_FRAME] = 0xff; + stat->ref1_counts[BWDREF_FRAME] = 0xff; + if (cpi->sf.use_first_partition_pass_interintra_stats) { + stat->interintra_motion_mode_count[ALTREF2_FRAME] = 0xff; + stat->interintra_motion_mode_count[BWDREF_FRAME] = 0xff; } } } } -static void init_simple_motion_search_mvs(PC_TREE *pc_tree) { - for (int idx = 0; idx < REF_FRAMES; idx++) { - pc_tree->mv_ref_fulls[idx].row = 0; - pc_tree->mv_ref_fulls[idx].col = 0; - } - if (pc_tree->block_size >= BLOCK_8X8) { - init_simple_motion_search_mvs(pc_tree->split[0]); - init_simple_motion_search_mvs(pc_tree->split[1]); - init_simple_motion_search_mvs(pc_tree->split[2]); - init_simple_motion_search_mvs(pc_tree->split[3]); - } -} - #define AVG_CDF_WEIGHT_LEFT 3 #define AVG_CDF_WEIGHT_TOP_RIGHT 1 @@ -5425,7 +4549,7 @@ static void avg_cdf_symbols(FRAME_CONTEXT *ctx_left, FRAME_CONTEXT *ctx_tr, AVERAGE_CDF(ctx_left->inter_compound_mode_cdf, ctx_tr->inter_compound_mode_cdf, INTER_COMPOUND_MODES); AVERAGE_CDF(ctx_left->compound_type_cdf, ctx_tr->compound_type_cdf, - COMPOUND_TYPES - 1); + MASKED_COMPOUND_TYPES); AVERAGE_CDF(ctx_left->wedge_idx_cdf, ctx_tr->wedge_idx_cdf, 16); AVERAGE_CDF(ctx_left->interintra_cdf, ctx_tr->interintra_cdf, 2); AVERAGE_CDF(ctx_left->wedge_interintra_cdf, ctx_tr->wedge_interintra_cdf, 2); @@ -5523,9 +4647,8 @@ static void avg_cdf_symbols(FRAME_CONTEXT *ctx_left, FRAME_CONTEXT *ctx_tr, CFL_ALPHABET_SIZE); } -static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, - TileDataEnc *tile_data, int mi_row, - TOKENEXTRA **tp) { +static void encode_sb_row(AV1_COMP *cpi, ThreadData *td, TileDataEnc *tile_data, + int mi_row, TOKENEXTRA **tp, int use_nonrd_mode) { AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); const TileInfo *const tile_info = &tile_data->tile_info; @@ -5539,6 +4662,10 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, const int mib_size_log2 = cm->seq_params.mib_size_log2; const int sb_row = (mi_row - tile_info->mi_row_start) >> mib_size_log2; +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, encode_sb_time); +#endif + // Initialize the left context for the new SB row av1_zero_left_context(xd); @@ -5572,8 +4699,32 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, wt_left, wt_tr); } } - av1_fill_coeff_costs(&td->mb, xd->tile_ctx, num_planes); - av1_fill_mode_rates(cm, x, xd->tile_ctx); + + switch (cpi->oxcf.coeff_cost_upd_freq) { + case COST_UPD_TILE: // Tile level + if (mi_row != tile_info->mi_row_start) break; + AOM_FALLTHROUGH_INTENDED; + case COST_UPD_SBROW: // SB row level in tile + if (mi_col != tile_info->mi_col_start) break; + AOM_FALLTHROUGH_INTENDED; + case COST_UPD_SB: // SB level + av1_fill_coeff_costs(&td->mb, xd->tile_ctx, num_planes); + break; + default: assert(0); + } + + switch (cpi->oxcf.mode_cost_upd_freq) { + case COST_UPD_TILE: // Tile level + if (mi_row != tile_info->mi_row_start) break; + AOM_FALLTHROUGH_INTENDED; + case COST_UPD_SBROW: // SB row level in tile + if (mi_col != tile_info->mi_col_start) break; + AOM_FALLTHROUGH_INTENDED; + case COST_UPD_SB: // SB level + av1_fill_mode_rates(cm, x, xd->tile_ctx); + break; + default: assert(0); + } if (sf->adaptive_pred_interp_filter) { for (int i = 0; i < leaf_nodes; ++i) { @@ -5586,17 +4737,24 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, x->mb_rd_record.num = x->mb_rd_record.index_start = 0; - av1_zero(x->txb_rd_record_8X8); - av1_zero(x->txb_rd_record_16X16); - av1_zero(x->txb_rd_record_32X32); - av1_zero(x->txb_rd_record_64X64); - av1_zero(x->txb_rd_record_intra); + if (!use_nonrd_mode) { + av1_zero(x->txb_rd_record_8X8); + av1_zero(x->txb_rd_record_16X16); + av1_zero(x->txb_rd_record_32X32); + av1_zero(x->txb_rd_record_64X64); + av1_zero(x->txb_rd_record_intra); + } + + av1_zero(x->picked_ref_frames_mask); av1_zero(x->pred_mv); PC_TREE *const pc_root = td->pc_root[mib_size_log2 - MIN_MIB_SIZE_LOG2]; pc_root->index = 0; - if (sf->simple_motion_search_prune_rect && !frame_is_intra_only(cm)) { + if ((sf->simple_motion_search_prune_rect || + sf->simple_motion_search_early_term_none || + sf->firstpass_simple_motion_search_early_term) && + !frame_is_intra_only(cm)) { init_simple_motion_search_mvs(pc_root); } @@ -5621,6 +4779,7 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, const int idx_str = cm->mi_stride * mi_row + mi_col; MB_MODE_INFO **mi = cm->mi_grid_visible + idx_str; x->source_variance = UINT_MAX; + x->simple_motion_pred_sse = UINT_MAX; if (sf->partition_search_type == FIXED_PARTITION || seg_skip) { set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); const BLOCK_SIZE bsize = seg_skip ? sb_size : sf->always_this_block_size; @@ -5634,6 +4793,13 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, set_fixed_partitioning(cpi, tile_info, mi, mi_row, mi_col, bsize); rd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size, &dummy_rate, &dummy_dist, 1, pc_root); + } else if (sf->partition_search_type == VAR_BASED_PARTITION && + use_nonrd_mode) { + set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); + av1_choose_var_based_partitioning(cpi, tile_info, x, mi_row, mi_col); + nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size, + &dummy_rate, &dummy_dist, 1, pc_root); + } else { const int orig_rdmult = cpi->rd.RDMULT; x->cb_rdmult = orig_rdmult; @@ -5646,28 +4812,67 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, x->rdmult = x->cb_rdmult; } - // If required set upper and lower partition size limits - if (sf->auto_min_max_partition_size) { - set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); - rd_auto_partition_range(cpi, tile_info, xd, mi_row, mi_col, - &x->min_partition_size, &x->max_partition_size); - } - reset_partition(pc_root, sb_size); x->use_cb_search_range = 0; - init_first_partition_pass_stats_tables(x->first_partition_pass_stats); +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, first_partition_search_pass_time); +#endif + init_first_partition_pass_stats_tables(cpi, + x->first_partition_pass_stats); // Do the first pass if we need two pass partition search - if (cpi->sf.two_pass_partition_search && + if (cpi->two_pass_partition_search && cpi->sf.use_square_partition_only_threshold > BLOCK_4X4 && - mi_row + mi_size_high[sb_size] < cm->mi_rows && - mi_col + mi_size_wide[sb_size] < cm->mi_cols && + mi_row + mi_size_high[sb_size] <= cm->mi_rows && + mi_col + mi_size_wide[sb_size] <= cm->mi_cols && cm->current_frame.frame_type != KEY_FRAME) { first_partition_search_pass(cpi, td, tile_data, mi_row, mi_col, tp); } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, first_partition_search_pass_time); +#endif + +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, rd_pick_partition_time); +#endif + BLOCK_SIZE max_sq_size = BLOCK_128X128; + switch (cpi->oxcf.max_partition_size) { + case 4: max_sq_size = BLOCK_4X4; break; + case 8: max_sq_size = BLOCK_8X8; break; + case 16: max_sq_size = BLOCK_16X16; break; + case 32: max_sq_size = BLOCK_32X32; break; + case 64: max_sq_size = BLOCK_64X64; break; + case 128: max_sq_size = BLOCK_128X128; break; + default: assert(0); break; + } + max_sq_size = AOMMIN(max_sq_size, sb_size); + + BLOCK_SIZE min_sq_size = BLOCK_4X4; + switch (cpi->oxcf.min_partition_size) { + case 4: min_sq_size = BLOCK_4X4; break; + case 8: min_sq_size = BLOCK_8X8; break; + case 16: min_sq_size = BLOCK_16X16; break; + case 32: min_sq_size = BLOCK_32X32; break; + case 64: min_sq_size = BLOCK_64X64; break; + case 128: min_sq_size = BLOCK_128X128; break; + default: assert(0); break; + } + + if (use_auto_max_partition(cpi, sb_size, mi_row, mi_col)) { + float features[FEATURE_SIZE_MAX_MIN_PART_PRED] = { 0.0f }; + + av1_get_max_min_partition_features(cpi, x, mi_row, mi_col, features); + max_sq_size = + AOMMIN(av1_predict_max_partition(cpi, x, features), max_sq_size); + } + + min_sq_size = AOMMIN(min_sq_size, max_sq_size); rd_pick_partition(cpi, td, tile_data, tp, mi_row, mi_col, sb_size, - sb_size, BLOCK_4X4, &dummy_rdc, INT64_MAX, pc_root, - NULL); + max_sq_size, min_sq_size, &dummy_rdc, INT64_MAX, + pc_root, NULL); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, rd_pick_partition_time); +#endif } // TODO(angiebird): Let inter_mode_rd_model_estimation support multi-tile. if (cpi->sf.inter_mode_rd_model_estimation == 1 && cm->tile_cols == 1 && @@ -5685,6 +4890,9 @@ static void encode_rd_sb_row(AV1_COMP *cpi, ThreadData *td, (*(cpi->row_mt_sync_write_ptr))(&tile_data->row_mt_sync, sb_row, sb_col_in_tile, sb_cols_in_tile); } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, encode_sb_time); +#endif } static void init_encode_frame_mb_context(AV1_COMP *cpi) { @@ -5702,18 +4910,18 @@ static void init_encode_frame_mb_context(AV1_COMP *cpi) { } static MV_REFERENCE_FRAME get_frame_type(const AV1_COMP *cpi) { - if (frame_is_intra_only(&cpi->common)) return INTRA_FRAME; - // We will not update the golden frame with an internal overlay frame - else if ((cpi->rc.is_src_frame_alt_ref && cpi->refresh_golden_frame) || - cpi->rc.is_src_frame_ext_arf) + if (frame_is_intra_only(&cpi->common)) { + return INTRA_FRAME; + } else if ((cpi->rc.is_src_frame_alt_ref && cpi->refresh_golden_frame) || + cpi->rc.is_src_frame_internal_arf) { + // We will not update the golden frame with an internal overlay frame return ALTREF_FRAME; - else if (cpi->refresh_golden_frame || cpi->refresh_alt2_ref_frame || - cpi->refresh_alt_ref_frame) + } else if (cpi->refresh_golden_frame || cpi->refresh_alt2_ref_frame || + cpi->refresh_alt_ref_frame) { return GOLDEN_FRAME; - else - // TODO(zoeliu): To investigate whether a frame_type other than - // INTRA/ALTREF/GOLDEN/LAST needs to be specified seperately. + } else { return LAST_FRAME; + } } static TX_MODE select_tx_mode(const AV1_COMP *cpi) { @@ -5804,7 +5012,7 @@ void av1_encode_sb_row(AV1_COMP *cpi, ThreadData *td, int tile_row, cm->seq_params.mib_size_log2 + MI_SIZE_LOG2, num_planes); cpi->tplist[tile_row][tile_col][sb_row_in_tile].start = tok; - encode_rd_sb_row(cpi, td, this_tile, mi_row, &tok); + encode_sb_row(cpi, td, this_tile, mi_row, &tok, cpi->sf.use_nonrd_pick_mode); cpi->tplist[tile_row][tile_col][sb_row_in_tile].stop = tok; cpi->tplist[tile_row][tile_col][sb_row_in_tile].count = @@ -5875,21 +5083,6 @@ static void encode_tiles(AV1_COMP *cpi) { } } -#if CONFIG_FP_MB_STATS -static int input_fpmb_stats(FIRSTPASS_MB_STATS *firstpass_mb_stats, - AV1_COMMON *cm, uint8_t **this_frame_mb_stats) { - uint8_t *mb_stats_in = - firstpass_mb_stats->mb_stats_start + - cm->current_frame.frame_number * cm->MBs * sizeof(uint8_t); - - if (mb_stats_in > firstpass_mb_stats->mb_stats_end) return EOF; - - *this_frame_mb_stats = mb_stats_in; - - return 1; -} -#endif - #define GLOBAL_TRANS_TYPES_ENC 3 // highest motion model to search static int gm_get_params_cost(const WarpedMotionParams *gm, const WarpedMotionParams *ref_gm, int allow_hp) { @@ -5957,97 +5150,54 @@ static int do_gm_search_logic(SPEED_FEATURES *const sf, int num_refs_using_gm, return 1; } -// Enforce the number of references for each arbitrary frame limited to -// (INTER_REFS_PER_FRAME - 1) +static int get_max_allowed_ref_frames(const AV1_COMP *cpi) { + const unsigned int max_allowed_refs_for_given_speed = + (cpi->sf.selective_ref_frame >= 3) ? INTER_REFS_PER_FRAME - 1 + : INTER_REFS_PER_FRAME; + return AOMMIN(max_allowed_refs_for_given_speed, + cpi->oxcf.max_reference_frames); +} + +// Enforce the number of references for each arbitrary frame based on user +// options and speed. static void enforce_max_ref_frames(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; MV_REFERENCE_FRAME ref_frame; int total_valid_refs = 0; for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - if (cpi->ref_frame_flags & ref_frame_flag_list[ref_frame]) + if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) { total_valid_refs++; + } } - // NOTE(zoeliu): When all the possible reference frames are availble, we - // reduce the number of reference frames by 1, following the rules of: - // (1) Retain GOLDEN_FARME/ALTEF_FRAME; - // (2) Check the earliest 2 remaining reference frames, and remove the one - // with the lower quality factor, otherwise if both have been coded at - // the same quality level, remove the earliest reference frame. + const int max_allowed_refs = get_max_allowed_ref_frames(cpi); - if (total_valid_refs == INTER_REFS_PER_FRAME) { - unsigned int min_ref_order_hint = UINT_MAX; - unsigned int second_min_ref_order_hint = UINT_MAX; - MV_REFERENCE_FRAME earliest_ref_frames[2] = { LAST3_FRAME, LAST2_FRAME }; - const RefCntBuffer *earliest_bufs[2] = { NULL }; + // When more than 'max_allowed_refs' are available, we reduce the number of + // reference frames one at a time based on this order. + const MV_REFERENCE_FRAME disable_order[] = { + LAST3_FRAME, + LAST2_FRAME, + ALTREF2_FRAME, + GOLDEN_FRAME, + }; - // Locate the earliest two reference frames except GOLDEN/ALTREF. - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - // Retain GOLDEN/ALTERF - if (ref_frame == GOLDEN_FRAME || ref_frame == ALTREF_FRAME) continue; + for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) { + const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i]; - const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame); - if (buf != NULL) { - const unsigned int ref_order_hint = buf->order_hint; - - if (min_ref_order_hint == UINT_MAX) { - min_ref_order_hint = ref_order_hint; - earliest_ref_frames[0] = ref_frame; - earliest_bufs[0] = buf; - } else { - if (get_relative_dist(&cm->seq_params.order_hint_info, ref_order_hint, - min_ref_order_hint) < 0) { - second_min_ref_order_hint = min_ref_order_hint; - earliest_ref_frames[1] = earliest_ref_frames[0]; - earliest_bufs[1] = earliest_bufs[0]; - - min_ref_order_hint = ref_order_hint; - earliest_ref_frames[0] = ref_frame; - earliest_bufs[0] = buf; - } else if (second_min_ref_order_hint == UINT_MAX || - get_relative_dist(&cm->seq_params.order_hint_info, - ref_order_hint, - second_min_ref_order_hint) < 0) { - second_min_ref_order_hint = ref_order_hint; - earliest_ref_frames[1] = ref_frame; - earliest_bufs[1] = buf; - } - } - } + if (!(cpi->ref_frame_flags & + av1_ref_frame_flag_list[ref_frame_to_disable])) { + continue; } - // Check the coding quality factors of the two earliest reference frames. - RATE_FACTOR_LEVEL ref_rf_level[2]; - double ref_rf_deltas[2]; - for (int i = 0; i < 2; ++i) { - ref_rf_level[i] = earliest_bufs[i]->frame_rf_level; - ref_rf_deltas[i] = rate_factor_deltas[ref_rf_level[i]]; - } - (void)ref_rf_level; - (void)ref_rf_deltas; - -#define USE_RF_LEVEL_TO_ENFORCE 1 -#if USE_RF_LEVEL_TO_ENFORCE - // If both earliest two reference frames are coded using the same rate- - // factor, disable the earliest reference frame; Otherwise disable the - // reference frame that uses a lower rate-factor delta. - const MV_REFERENCE_FRAME ref_frame_to_disable = - (ref_rf_deltas[0] <= ref_rf_deltas[1]) ? earliest_ref_frames[0] - : earliest_ref_frames[1]; -#else - // Always disable the earliest reference frame - const MV_REFERENCE_FRAME ref_frame_to_disable = earliest_ref_frames[0]; -#endif // USE_RF_LEVEL_TO_ENFORCE -#undef USE_RF_LEVEL_TO_ENFORCE switch (ref_frame_to_disable) { - case LAST_FRAME: cpi->ref_frame_flags &= ~AOM_LAST_FLAG; break; - case LAST2_FRAME: cpi->ref_frame_flags &= ~AOM_LAST2_FLAG; break; case LAST3_FRAME: cpi->ref_frame_flags &= ~AOM_LAST3_FLAG; break; - case BWDREF_FRAME: cpi->ref_frame_flags &= ~AOM_BWD_FLAG; break; + case LAST2_FRAME: cpi->ref_frame_flags &= ~AOM_LAST2_FLAG; break; case ALTREF2_FRAME: cpi->ref_frame_flags &= ~AOM_ALT2_FLAG; break; - default: break; + case GOLDEN_FRAME: cpi->ref_frame_flags &= ~AOM_GOLD_FLAG; break; + default: assert(0); } + --total_valid_refs; } + assert(total_valid_refs <= max_allowed_refs); } static INLINE int av1_refs_are_one_sided(const AV1_COMMON *cm) { @@ -6164,9 +5314,10 @@ static void encode_frame_internal(AV1_COMP *cpi) { av1_zero(*td->counts); av1_zero(rdc->comp_pred_diff); + // Two pass partition search can be enabled/disabled for different frames. + // Reset this data at frame level to avoid any incorrect usage. + init_first_partition_pass_stats_tables(cpi, x->first_partition_pass_stats); - // Allow intrabc when screen content tools are enabled. - cm->allow_intrabc = cm->allow_screen_content_tools; // Reset the flag. cpi->intrabc_used = 0; // Need to disable intrabc when superres is selected @@ -6174,6 +5325,8 @@ static void encode_frame_internal(AV1_COMP *cpi) { cm->allow_intrabc = 0; } + cm->allow_intrabc &= (cpi->oxcf.enable_intrabc); + if (cpi->oxcf.pass != 1 && av1_use_hash_me(cm)) { // add to hash table const int pic_width = cpi->source->y_crop_width; @@ -6258,7 +5411,7 @@ static void encode_frame_internal(AV1_COMP *cpi) { if (xd->lossless[i]) { cpi->optimize_seg_arr[i] = 0; } else { - cpi->optimize_seg_arr[i] = cpi->optimize_speed_feature; + cpi->optimize_seg_arr[i] = cpi->sf.optimize_coefficients; } } cm->coded_lossless = is_coded_lossless(cm, xd); @@ -6300,8 +5453,7 @@ static void encode_frame_internal(AV1_COMP *cpi) { aom_clear_system_state(); if (tpl_frame->is_valid) - cpi->rd.r0 = - (double)intra_cost_base / (intra_cost_base + mc_dep_cost_base); + cpi->rd.r0 = (double)intra_cost_base / mc_dep_cost_base; } av1_frame_init_quantizer(cpi); @@ -6333,6 +5485,9 @@ static void encode_frame_internal(AV1_COMP *cpi) { x->tx_search_count = 0; #endif // CONFIG_SPEED_STATS +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, av1_compute_global_motion_time); +#endif av1_zero(rdc->global_motion_used); av1_zero(cpi->gmparams_cost); if (cpi->common.current_frame.frame_type == INTER_FRAME && cpi->source && @@ -6380,6 +5535,18 @@ static void encode_frame_internal(AV1_COMP *cpi) { if (ref_frame_error == 0) continue; aom_clear_system_state(); + + // TODO(sarahparker, debargha): Explore do_adaptive_gm_estimation = 1 + const int do_adaptive_gm_estimation = 0; + + const int ref_frame_dist = get_relative_dist( + &cm->seq_params.order_hint_info, cm->current_frame.order_hint, + cm->cur_frame->ref_order_hints[frame - LAST_FRAME]); + const GlobalMotionEstimationType gm_estimation_type = + cm->seq_params.order_hint_info.enable_order_hint && + abs(ref_frame_dist) <= 2 && do_adaptive_gm_estimation + ? GLOBAL_MOTION_DISFLOW_BASED + : GLOBAL_MOTION_FEATURE_BASED; for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES_ENC; ++model) { int64_t best_warp_error = INT64_MAX; // Initially set all params to identity. @@ -6390,8 +5557,8 @@ static void encode_frame_internal(AV1_COMP *cpi) { av1_compute_global_motion(model, cpi->source, ref_buf[frame], cpi->common.seq_params.bit_depth, - inliers_by_motion, params_by_motion, - RANSAC_NUM_MOTIONS); + gm_estimation_type, inliers_by_motion, + params_by_motion, RANSAC_NUM_MOTIONS); for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) { if (inliers_by_motion[i] == 0) continue; @@ -6455,7 +5622,7 @@ static void encode_frame_internal(AV1_COMP *cpi) { // clear disabled ref_frames for (frame = LAST_FRAME; frame <= ALTREF_FRAME; ++frame) { const int ref_disabled = - !(cpi->ref_frame_flags & ref_frame_flag_list[frame]); + !(cpi->ref_frame_flags & av1_ref_frame_flag_list[frame]); if (ref_disabled && cpi->sf.recode_loop != DISALLOW_RECODE) { cpi->gmparams_cost[frame] = 0; cm->global_motion[frame] = default_warp_params; @@ -6465,8 +5632,17 @@ static void encode_frame_internal(AV1_COMP *cpi) { } memcpy(cm->cur_frame->global_motion, cm->global_motion, REF_FRAMES * sizeof(WarpedMotionParams)); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, av1_compute_global_motion_time); +#endif +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, av1_setup_motion_field_time); +#endif av1_setup_motion_field(cm); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, av1_setup_motion_field_time); +#endif cpi->all_one_sided_refs = frame_is_intra_only(cm) ? 0 : av1_refs_are_one_sided(cm); @@ -6475,13 +5651,6 @@ static void encode_frame_internal(AV1_COMP *cpi) { check_skip_mode_enabled(cpi); { -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - input_fpmb_stats(&cpi->twopass.firstpass_mb_stats, cm, - &cpi->twopass.this_frame_mb_stats); - } -#endif - cpi->row_mt_sync_read_ptr = av1_row_mt_sync_read_dummy; cpi->row_mt_sync_write_ptr = av1_row_mt_sync_write_dummy; cpi->row_mt = 0; @@ -6526,9 +5695,7 @@ void av1_encode_frame(AV1_COMP *cpi) { } av1_setup_frame_buf_refs(cm); - if (cpi->sf.selective_ref_frame >= 3 && cpi->oxcf.max_reference_frames == 7) { - enforce_max_ref_frames(cpi); - } + enforce_max_ref_frames(cpi); av1_setup_frame_sign_bias(cm); #if CONFIG_MISMATCH_DEBUG @@ -6767,8 +5934,7 @@ static void encode_superblock(const AV1_COMP *const cpi, TileDataEnc *tile_data, const int mi_height = mi_size_high[bsize]; const int is_inter = is_inter_block(mbmi); - if (cpi->sf.mode_pruning_based_on_two_pass_partition_search && - x->cb_partition_scan) { + if (cpi->two_pass_partition_search && x->cb_partition_scan) { for (int row = mi_row; row < mi_row + mi_width; row += FIRST_PARTITION_PASS_SAMPLE_REGION) { for (int col = mi_col; col < mi_col + mi_height; @@ -6782,8 +5948,15 @@ static void encode_superblock(const AV1_COMP *const cpi, TileDataEnc *tile_data, if (stats->ref0_counts[mbmi->ref_frame[0]] < 255) ++stats->ref0_counts[mbmi->ref_frame[0]]; if (mbmi->ref_frame[1] >= 0 && - stats->ref1_counts[mbmi->ref_frame[0]] < 255) + stats->ref1_counts[mbmi->ref_frame[1]] < 255) ++stats->ref1_counts[mbmi->ref_frame[1]]; + if (cpi->sf.use_first_partition_pass_interintra_stats) { + // Increase the counter for interintra_motion_mode_count + if (mbmi->motion_mode == 0 && mbmi->ref_frame[1] == INTRA_FRAME && + stats->interintra_motion_mode_count[mbmi->ref_frame[0]] < 255) { + ++stats->interintra_motion_mode_count[mbmi->ref_frame[0]]; + } + } } } } diff --git a/third_party/aom/av1/encoder/encodemb.c b/third_party/aom/av1/encoder/encodemb.c index 6edb0f88cd..8e9da6166b 100644 --- a/third_party/aom/av1/encoder/encodemb.c +++ b/third_party/aom/av1/encoder/encodemb.c @@ -111,9 +111,8 @@ int av1_optimize_b(const struct AV1_COMP *cpi, MACROBLOCK *mb, int plane, return eob; } - (void)fast_mode; return av1_optimize_txb_new(cpi, mb, plane, block, tx_size, tx_type, txb_ctx, - rate_cost, cpi->oxcf.sharpness); + rate_cost, cpi->oxcf.sharpness, fast_mode); } enum { @@ -185,7 +184,7 @@ void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block, av1_quantize_skip(n_coeffs, qcoeff, dqcoeff, eob); } } - // NOTE: optimize_b_following is ture means av1_optimze_b will be called + // NOTE: optimize_b_following is true means av1_optimze_b will be called // When the condition of doing optimize_b is changed, // this flag need update simultaneously const int optimize_b_following = @@ -228,12 +227,16 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, TX_TYPE tx_type = av1_get_tx_type(pd->plane_type, xd, blk_row, blk_col, tx_size, cm->reduced_tx_set_used); if (args->enable_optimize_b != NO_TRELLIS_OPT) { - av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, - tx_size, tx_type, AV1_XFORM_QUANT_FP); + av1_xform_quant( + cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type, + USE_B_QUANT_NO_TRELLIS && + (args->enable_optimize_b == FINAL_PASS_TRELLIS_OPT) + ? AV1_XFORM_QUANT_B + : AV1_XFORM_QUANT_FP); TXB_CTX txb_ctx; get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx); - av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx, 1, - &dummy_rate_cost); + av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx, + args->cpi->sf.trellis_eob_fast, &dummy_rate_cost); } else { av1_xform_quant( cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type, @@ -256,12 +259,12 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, cm->reduced_tx_set_used); } + // TODO(debargha, jingning): Temporarily disable txk_type check for eob=0 + // case. It is possible that certain collision in hash index would cause + // the assertion failure. To further optimize the rate-distortion + // performance, we need to re-visit this part and enable this assert + // again. if (p->eobs[block] == 0 && plane == 0) { - // TODO(debargha, jingning): Temporarily disable txk_type check for eob=0 - // case. It is possible that certain collision in hash index would cause - // the assertion failure. To further optimize the rate-distortion - // performance, we need to re-visit this part and enable this assert - // again. #if 0 if (args->cpi->oxcf.aq_mode == NO_AQ && args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) { @@ -580,12 +583,16 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col, const ENTROPY_CONTEXT *a = &args->ta[blk_col]; const ENTROPY_CONTEXT *l = &args->tl[blk_row]; if (args->enable_optimize_b != NO_TRELLIS_OPT) { - av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, - tx_size, tx_type, AV1_XFORM_QUANT_FP); + av1_xform_quant( + cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type, + USE_B_QUANT_NO_TRELLIS && + (args->enable_optimize_b == FINAL_PASS_TRELLIS_OPT) + ? AV1_XFORM_QUANT_B + : AV1_XFORM_QUANT_FP); TXB_CTX txb_ctx; get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx); - av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx, 1, - &dummy_rate_cost); + av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx, + args->cpi->sf.trellis_eob_fast, &dummy_rate_cost); } else { av1_xform_quant( cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type, @@ -598,12 +605,12 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col, dst_stride, *eob, cm->reduced_tx_set_used); } + // TODO(jingning): Temporarily disable txk_type check for eob=0 case. + // It is possible that certain collision in hash index would cause + // the assertion failure. To further optimize the rate-distortion + // performance, we need to re-visit this part and enable this assert + // again. if (*eob == 0 && plane == 0) { - // TODO(jingning): Temporarily disable txk_type check for eob=0 case. - // It is possible that certain collision in hash index would cause - // the assertion failure. To further optimize the rate-distortion - // performance, we need to re-visit this part and enable this assert - // again. #if 0 if (args->cpi->oxcf.aq_mode == NO_AQ && args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) { diff --git a/third_party/aom/av1/encoder/encoder.c b/third_party/aom/av1/encoder/encoder.c index 9428a92740..7716ee2000 100644 --- a/third_party/aom/av1/encoder/encoder.c +++ b/third_party/aom/av1/encoder/encoder.c @@ -62,6 +62,7 @@ #include "av1/encoder/grain_test_vectors.h" #include "av1/encoder/hash_motion.h" #include "av1/encoder/mbgraph.h" +#include "av1/encoder/pass2_strategy.h" #include "av1/encoder/picklpf.h" #include "av1/encoder/pickrst.h" #include "av1/encoder/random.h" @@ -71,6 +72,7 @@ #include "av1/encoder/segmentation.h" #include "av1/encoder/speed_features.h" #include "av1/encoder/reconinter_enc.h" +#include "av1/encoder/var_based_part.h" #define DEFAULT_EXPLICIT_ORDER_HINT_BITS 7 @@ -97,30 +99,6 @@ FILE *yuv_rec_file; #define FILE_NAME_LEN 100 #endif -// Estimate if the source frame is screen content, based on the portion of -// blocks that have no more than 4 (experimentally selected) luma colors. -static int is_screen_content(const uint8_t *src, int use_hbd, int bd, - int stride, int width, int height) { - assert(src != NULL); - int counts = 0; - const int blk_w = 16; - const int blk_h = 16; - const int limit = 4; - for (int r = 0; r + blk_h <= height; r += blk_h) { - for (int c = 0; c + blk_w <= width; c += blk_w) { - int count_buf[1 << 12]; // Maximum (1 << 12) color levels. - const int n_colors = - use_hbd ? av1_count_colors_highbd(src + r * stride + c, stride, blk_w, - blk_h, bd, count_buf) - : av1_count_colors(src + r * stride + c, stride, blk_w, blk_h, - count_buf); - if (n_colors > 1 && n_colors <= limit) counts++; - } - } - // The threshold is 10%. - return counts * blk_h * blk_w * 10 > width * height; -} - static INLINE void Scale2Ratio(AOM_SCALING mode, int *hr, int *hs) { switch (mode) { case NORMAL: @@ -380,14 +358,8 @@ static void setup_frame(AV1_COMP *cpi) { } if (cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) { - cpi->refresh_golden_frame = 1; - cpi->refresh_alt_ref_frame = 1; - av1_zero(cpi->interp_filter_selected); set_sb_size(&cm->seq_params, select_sb_size(cpi)); } else if (frame_is_sframe(cm)) { - cpi->refresh_golden_frame = 1; - cpi->refresh_alt_ref_frame = 1; - av1_zero(cpi->interp_filter_selected); set_sb_size(&cm->seq_params, select_sb_size(cpi)); } else { const RefCntBuffer *const primary_ref_buf = get_primary_ref_frame_buf(cm); @@ -398,9 +370,9 @@ static void setup_frame(AV1_COMP *cpi) { } else { *cm->fc = primary_ref_buf->frame_context; } - av1_zero(cpi->interp_filter_selected[0]); } + av1_zero(cm->cur_frame->interp_filter_selected); cm->prev_frame = get_primary_ref_frame_buf(cm); cpi->vaq_refresh = 0; } @@ -534,13 +506,19 @@ static void update_film_grain_parameters(struct AV1_COMP *cpi, } } } else if (oxcf->film_grain_table_filename) { + cm->seq_params.film_grain_params_present = 1; + cpi->film_grain_table = aom_malloc(sizeof(*cpi->film_grain_table)); memset(cpi->film_grain_table, 0, sizeof(aom_film_grain_table_t)); aom_film_grain_table_read(cpi->film_grain_table, oxcf->film_grain_table_filename, &cm->error); } else { +#if CONFIG_DENOISE + cm->seq_params.film_grain_params_present = (cpi->oxcf.noise_level > 0); +#else cm->seq_params.film_grain_params_present = 0; +#endif memset(&cm->film_grain_params, 0, sizeof(cm->film_grain_params)); } } @@ -809,11 +787,13 @@ static void alloc_raw_frame_buffers(AV1_COMP *cpi) { const SequenceHeader *const seq_params = &cm->seq_params; const AV1EncoderConfig *oxcf = &cpi->oxcf; - if (!cpi->lookahead) + if (!cpi->lookahead) { + int is_scale = (oxcf->resize_mode || oxcf->superres_mode); cpi->lookahead = av1_lookahead_init( oxcf->width, oxcf->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - oxcf->lag_in_frames, oxcf->border_in_pixels); + oxcf->lag_in_frames, oxcf->border_in_pixels, is_scale); + } if (!cpi->lookahead) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate lag buffers"); @@ -984,77 +964,58 @@ static void set_bitstream_level_tier(SequenceHeader *seq, AV1_COMMON *cm, // and max display sample rates. // Need to add checks for max bit rate, max decoded luma sample rate, header // rate, etc. that are not covered by this function. - (void)oxcf; - BitstreamLevel bl = { 9, 3 }; + AV1_LEVEL level = SEQ_LEVEL_MAX; if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 512, 288, 30.0, 4)) { - bl.major = 2; - bl.minor = 0; + level = SEQ_LEVEL_2_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 704, 396, 30.0, 4)) { - bl.major = 2; - bl.minor = 1; + level = SEQ_LEVEL_2_1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 1088, 612, 30.0, 4)) { - bl.major = 3; - bl.minor = 0; + level = SEQ_LEVEL_3_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 1376, 774, 30.0, 4)) { - bl.major = 3; - bl.minor = 1; + level = SEQ_LEVEL_3_1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 2048, 1152, 30.0, 3)) { - bl.major = 4; - bl.minor = 0; + level = SEQ_LEVEL_4_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 2048, 1152, 60.0, 3)) { - bl.major = 4; - bl.minor = 1; + level = SEQ_LEVEL_4_1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 4096, 2176, 30.0, 2)) { - bl.major = 5; - bl.minor = 0; + level = SEQ_LEVEL_5_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 4096, 2176, 60.0, 2)) { - bl.major = 5; - bl.minor = 1; + level = SEQ_LEVEL_5_1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 4096, 2176, 120.0, 2)) { - bl.major = 5; - bl.minor = 2; + level = SEQ_LEVEL_5_2; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 8192, 4352, 30.0, 2)) { - bl.major = 6; - bl.minor = 0; + level = SEQ_LEVEL_6_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 8192, 4352, 60.0, 2)) { - bl.major = 6; - bl.minor = 1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 8192, 4352, 120.0, 2)) { - bl.major = 6; - bl.minor = 2; + level = SEQ_LEVEL_6_2; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 16384, 8704, 30.0, 2)) { - bl.major = 7; - bl.minor = 0; + level = SEQ_LEVEL_7_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 16384, 8704, 60.0, 2)) { - bl.major = 7; - bl.minor = 1; + level = SEQ_LEVEL_7_1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 16384, 8704, 120.0, 2)) { - bl.major = 7; - bl.minor = 2; + level = SEQ_LEVEL_7_2; } for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { - seq->level[i] = bl; - seq->tier[i] = 0; // setting main tier by default + seq->seq_level_idx[i] = level; // Set the maximum parameters for bitrate and buffer size for this profile, // level, and tier cm->op_params[i].bitrate = max_level_bitrate( - cm->seq_params.profile, major_minor_to_seq_level_idx(seq->level[i]), - seq->tier[i]); + cm->seq_params.profile, seq->seq_level_idx[i], seq->tier[i]); // Level with seq_level_idx = 31 returns a high "dummy" bitrate to pass the // check if (cm->op_params[i].bitrate == 0) @@ -2434,6 +2395,16 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { assert(IMPLIES(seq_params->profile <= PROFILE_1, seq_params->bit_depth <= AOM_BITS_10)); + memcpy(cpi->target_seq_level_idx, oxcf->target_seq_level_idx, + sizeof(cpi->target_seq_level_idx)); + cpi->keep_level_stats = 0; + for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { + if (cpi->target_seq_level_idx[i] < SEQ_LEVELS) { + cpi->keep_level_stats = 1; + break; + } + } + cm->timing_info_present = oxcf->timing_info_present; cm->timing_info.num_units_in_display_tick = oxcf->timing_info.num_units_in_display_tick; @@ -2542,6 +2513,8 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { // Superblock size should not be updated after the first key frame. if (!cpi->seq_params_locked) { set_sb_size(&cm->seq_params, select_sb_size(cpi)); + for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) + seq_params->tier[i] = (oxcf->tier_mask >> i) & 1; } if (cpi->initial_width || sb_size != seq_params->sb_size) { @@ -2559,10 +2532,6 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { cpi->alt_ref_source = NULL; rc->is_src_frame_alt_ref = 0; - rc->is_bwd_ref_frame = 0; - rc->is_last_bipred_frame = 0; - rc->is_bipred_frame = 0; - set_tile_info(cpi); cpi->ext_refresh_frame_flags_pending = 0; @@ -2579,6 +2548,19 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { } } +static void init_level_info(AV1LevelInfo *level_info) { + memset(level_info, 0, MAX_NUM_OPERATING_POINTS * sizeof(*level_info)); + for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { + AV1LevelSpec *const level_spec = &level_info[i].level_spec; + level_spec->level = SEQ_LEVEL_MAX; + AV1LevelStats *const level_stats = &level_info[i].level_stats; + level_stats->min_cropped_tile_width = INT_MAX; + level_stats->min_cropped_tile_height = INT_MAX; + level_stats->tile_width_is_valid = 1; + level_stats->min_cr = 1e8; + } +} + AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, BufferPool *const pool) { unsigned int i; @@ -2638,19 +2620,10 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, aom_calloc(cm->MBs * sizeof(*cpi->mbgraph_stats[i].mb_stats), 1)); } -#if CONFIG_FP_MB_STATS - cpi->use_fp_mb_stats = 0; - if (cpi->use_fp_mb_stats) { - // a place holder used to store the first pass mb stats in the first pass - CHECK_MEM_ERROR(cm, cpi->twopass.frame_mb_stats_buf, - aom_calloc(cm->MBs * sizeof(uint8_t), 1)); - } else { - cpi->twopass.frame_mb_stats_buf = NULL; - } -#endif - cpi->refresh_alt_ref_frame = 0; + init_level_info(cpi->level_info); + cpi->b_calculate_psnr = CONFIG_INTERNAL_STATS; #if CONFIG_INTERNAL_STATS cpi->b_calculate_blockiness = 1; @@ -2712,19 +2685,6 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int packets = (int)(oxcf->two_pass_stats_in.sz / packet_sz); -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - const size_t psz = cpi->common.MBs * sizeof(uint8_t); - const int ps = (int)(oxcf->firstpass_mb_stats_in.sz / psz); - - cpi->twopass.firstpass_mb_stats.mb_stats_start = - oxcf->firstpass_mb_stats_in.buf; - cpi->twopass.firstpass_mb_stats.mb_stats_end = - cpi->twopass.firstpass_mb_stats.mb_stats_start + - (ps - 1) * cpi->common.MBs * sizeof(uint8_t); - } -#endif - cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf; cpi->twopass.stats_in = cpi->twopass.stats_in_start; cpi->twopass.stats_in_end = &cpi->twopass.stats_in[packets - 1]; @@ -2780,7 +2740,7 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, cpi->tpl_stats[frame].mi_cols = cm->mi_cols; } -#if CONFIG_COLLECT_PARTITION_STATS +#if CONFIG_COLLECT_PARTITION_STATS == 2 av1_zero(cpi->partition_stats); #endif @@ -3102,7 +3062,7 @@ void av1_remove_compressor(AV1_COMP *cpi) { } #endif // CONFIG_SPEED_STATS -#if CONFIG_COLLECT_PARTITION_STATS +#if CONFIG_COLLECT_PARTITION_STATS == 2 if (cpi->oxcf.pass != 1) { av1_print_partition_stats(&cpi->partition_stats); } @@ -3170,12 +3130,6 @@ void av1_remove_compressor(AV1_COMP *cpi) { aom_free(cpi->mbgraph_stats[i].mb_stats); } -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - aom_free(cpi->twopass.frame_mb_stats_buf); - cpi->twopass.frame_mb_stats_buf = NULL; - } -#endif #if CONFIG_INTERNAL_STATS aom_free(cpi->ssim_vars); cpi->ssim_vars = NULL; @@ -3390,344 +3344,6 @@ static int recode_loop_test(AV1_COMP *cpi, int high_limit, int low_limit, int q, return force_recode; } -#define DUMP_REF_FRAME_IMAGES 0 - -#if DUMP_REF_FRAME_IMAGES == 1 -static int dump_one_image(AV1_COMMON *cm, - const YV12_BUFFER_CONFIG *const ref_buf, - char *file_name) { - int h; - FILE *f_ref = NULL; - - if (ref_buf == NULL) { - printf("Frame data buffer is NULL.\n"); - return AOM_CODEC_MEM_ERROR; - } - - if ((f_ref = fopen(file_name, "wb")) == NULL) { - printf("Unable to open file %s to write.\n", file_name); - return AOM_CODEC_MEM_ERROR; - } - - // --- Y --- - for (h = 0; h < cm->height; ++h) { - fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref); - } - // --- U --- - for (h = 0; h < (cm->height >> 1); ++h) { - fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), - f_ref); - } - // --- V --- - for (h = 0; h < (cm->height >> 1); ++h) { - fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1), - f_ref); - } - - fclose(f_ref); - - return AOM_CODEC_OK; -} - -static void dump_ref_frame_images(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - MV_REFERENCE_FRAME ref_frame; - - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - char file_name[256] = ""; - snprintf(file_name, sizeof(file_name), "/tmp/enc_F%d_ref_%d.yuv", - cm->current_frame.frame_number, ref_frame); - dump_one_image(cm, get_ref_frame_yv12_buf(cpi, ref_frame), file_name); - } -} -#endif // DUMP_REF_FRAME_IMAGES == 1 - -// This function is used to shift the virtual indices of last reference frames -// as follows: -// LAST_FRAME -> LAST2_FRAME -> LAST3_FRAME -// when the LAST_FRAME is updated. -static INLINE void shift_last_ref_frames(AV1_COMP *cpi) { - // TODO(isbs): shift the scaled indices as well - for (int ref_frame = LAST3_FRAME; ref_frame > LAST_FRAME; --ref_frame) { - const int ref_idx = ref_frame - LAST_FRAME; - cpi->common.remapped_ref_idx[ref_idx] = - cpi->common.remapped_ref_idx[ref_idx - 1]; - - if (!cpi->rc.is_src_frame_alt_ref) { - memcpy(cpi->interp_filter_selected[ref_frame], - cpi->interp_filter_selected[ref_frame - 1], - sizeof(cpi->interp_filter_selected[ref_frame - 1])); - } - } -} - -// This function is used to shift the virtual indices of bwd reference -// frames as follows: -// BWD_REF -> ALT2_REF -> EXT_REF -// to clear a space to store the closest bwdref -static INLINE void rshift_bwd_ref_frames(AV1_COMP *cpi) { - // TODO(isbs): shift the scaled indices as well - static const int ordered_bwd[3] = { BWDREF_FRAME, ALTREF2_FRAME, - EXTREF_FRAME }; - - for (int i = 2; i > 0; --i) { - // [0] is allocated to the current coded frame, i.e. bwdref - memcpy(cpi->interp_filter_selected[ordered_bwd[i]], - cpi->interp_filter_selected[ordered_bwd[i - 1]], - sizeof(cpi->interp_filter_selected[ordered_bwd[i - 1]])); - - cpi->common.remapped_ref_idx[ordered_bwd[i] - LAST_FRAME] = - cpi->common.remapped_ref_idx[ordered_bwd[i - 1] - LAST_FRAME]; - } -} - -// This function is used to shift the virtual indices of bwd reference -// frames as follows: -// BWD_REF <- ALT2_REF <- EXT_REF -// to update the bwd reference frame for coding the next frame. -static INLINE void lshift_bwd_ref_frames(AV1_COMP *cpi) { - // TODO(isbs): shift the scaled indices as well - static const int ordered_bwd[3] = { BWDREF_FRAME, ALTREF2_FRAME, - EXTREF_FRAME }; - - for (int i = 0; i < 2; ++i) { - // [0] is allocated to the current coded frame, i.e. bwdref - memcpy(cpi->interp_filter_selected[ordered_bwd[i]], - cpi->interp_filter_selected[ordered_bwd[i + 1]], - sizeof(cpi->interp_filter_selected[ordered_bwd[i + 1]])); - - cpi->common.remapped_ref_idx[ordered_bwd[i] - LAST_FRAME] = - cpi->common.remapped_ref_idx[ordered_bwd[i + 1] - LAST_FRAME]; - } -} - -static void update_reference_frames(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - - // NOTE: Save the new show frame buffer index for --test-code=warn, i.e., - // for the purpose to verify no mismatch between encoder and decoder. - if (cm->show_frame) cpi->last_show_frame_buf = cm->cur_frame; - - // In the case of show_existing frame, we will not send fresh flag - // to decoder. Any change in the reference frame buffer can be done by - // switching the virtual indices. - if (cm->show_existing_frame) { - // If we are not indicating to the decoder that this frame is - // a show_existing_frame, which occurs in error_resilient mode, - // we still want to refresh the LAST_FRAME when the current frame - // was the source of an ext_arf. - cpi->refresh_last_frame = - !encode_show_existing_frame(cm) && cpi->rc.is_src_frame_ext_arf; - cpi->refresh_golden_frame = 0; - cpi->refresh_bwd_ref_frame = 0; - cpi->refresh_alt2_ref_frame = 0; - cpi->refresh_alt_ref_frame = 0; - - cpi->rc.is_bwd_ref_frame = 0; - cpi->rc.is_last_bipred_frame = 0; - cpi->rc.is_bipred_frame = 0; - } - - // At this point the new frame has been encoded. - // If any buffer copy / swapping is signaled it should be done here. - - // Only update all of the reference buffers if a KEY_FRAME is also a - // show_frame. This ensures a fwd keyframe does not update all of the buffers - if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) || - frame_is_sframe(cm)) { - for (int ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame) { - assign_frame_buffer_p(&cm->ref_frame_map[cm->remapped_ref_idx[ref_frame]], - cm->cur_frame); - } - return; - } - - if (av1_preserve_existing_gf(cpi)) { - // We have decided to preserve the previously existing golden frame as our - // new ARF frame. However, in the short term in function - // av1_bitstream.c::get_refresh_mask() we left it in the GF slot and, if - // we're updating the GF with the current decoded frame, we save it to the - // ARF slot instead. - // We now have to update the ARF with the current frame and swap gld_fb_idx - // and alt_fb_idx so that, overall, we've stored the old GF in the new ARF - // slot and, if we're updating the GF, the current frame becomes the new GF. - int tmp; - - // ARF in general is a better reference than overlay. We shouldkeep ARF as - // reference instead of replacing it with overlay. - - if (!cpi->preserve_arf_as_gld) { - assign_frame_buffer_p( - &cm->ref_frame_map[get_ref_frame_map_idx(cm, ALTREF_FRAME)], - cm->cur_frame); - } - - tmp = get_ref_frame_map_idx(cm, ALTREF_FRAME); - cm->remapped_ref_idx[ALTREF_FRAME - LAST_FRAME] = - get_ref_frame_map_idx(cm, GOLDEN_FRAME); - cm->remapped_ref_idx[GOLDEN_FRAME - LAST_FRAME] = tmp; - - // TODO(zoeliu): Do we need to copy cpi->interp_filter_selected[0] over to - // cpi->interp_filter_selected[GOLDEN_FRAME]? - } else if (cpi->rc.is_src_frame_ext_arf && encode_show_existing_frame(cm)) { -#if CONFIG_DEBUG - const GF_GROUP *const gf_group = &cpi->twopass.gf_group; - assert(gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE); -#endif // CONFIG_DEBUG - const int bwdref_to_show = - (cpi->new_bwdref_update_rule == 1) ? BWDREF_FRAME : ALTREF2_FRAME; - // Deal with the special case for showing existing internal ALTREF_FRAME - // Refresh the LAST_FRAME with the ALTREF_FRAME and retire the LAST3_FRAME - // by updating the virtual indices. - const int last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME); - shift_last_ref_frames(cpi); - - cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] = - get_ref_frame_map_idx(cm, bwdref_to_show); - - memcpy(cpi->interp_filter_selected[LAST_FRAME], - cpi->interp_filter_selected[bwdref_to_show], - sizeof(cpi->interp_filter_selected[bwdref_to_show])); - if (cpi->new_bwdref_update_rule == 1) { - lshift_bwd_ref_frames(cpi); - // pass outdated forward reference frame (previous LAST3) to the - // spared space - cm->remapped_ref_idx[EXTREF_FRAME - LAST_FRAME] = last3_remapped_idx; - } else { - cm->remapped_ref_idx[bwdref_to_show - LAST_FRAME] = last3_remapped_idx; - } - } else { /* For non key/golden frames */ - // === ALTREF_FRAME === - if (cpi->refresh_alt_ref_frame) { - int arf_idx = get_ref_frame_map_idx(cm, ALTREF_FRAME); - assign_frame_buffer_p(&cm->ref_frame_map[arf_idx], cm->cur_frame); - - memcpy(cpi->interp_filter_selected[ALTREF_FRAME], - cpi->interp_filter_selected[0], - sizeof(cpi->interp_filter_selected[0])); - } - - // === GOLDEN_FRAME === - if (cpi->refresh_golden_frame) { - assign_frame_buffer_p( - &cm->ref_frame_map[get_ref_frame_map_idx(cm, GOLDEN_FRAME)], - cm->cur_frame); - - memcpy(cpi->interp_filter_selected[GOLDEN_FRAME], - cpi->interp_filter_selected[0], - sizeof(cpi->interp_filter_selected[0])); - } - - // === BWDREF_FRAME === - if (cpi->refresh_bwd_ref_frame) { - if (cpi->new_bwdref_update_rule) { - // We shift the backward reference frame as follows: - // BWDREF -> ALTREF2 -> EXTREF - // and assign the newly coded frame to BWDREF so that it always - // keeps the nearest future frame - const int tmp = get_ref_frame_map_idx(cm, EXTREF_FRAME); - assign_frame_buffer_p(&cm->ref_frame_map[tmp], cm->cur_frame); - - rshift_bwd_ref_frames(cpi); - cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = tmp; - } else { - assign_frame_buffer_p( - &cm->ref_frame_map[get_ref_frame_map_idx(cm, BWDREF_FRAME)], - cm->cur_frame); - } - memcpy(cpi->interp_filter_selected[BWDREF_FRAME], - cpi->interp_filter_selected[0], - sizeof(cpi->interp_filter_selected[0])); - } - - // === ALTREF2_FRAME === - if (cpi->refresh_alt2_ref_frame) { - assign_frame_buffer_p( - &cm->ref_frame_map[get_ref_frame_map_idx(cm, ALTREF2_FRAME)], - cm->cur_frame); - - memcpy(cpi->interp_filter_selected[ALTREF2_FRAME], - cpi->interp_filter_selected[0], - sizeof(cpi->interp_filter_selected[0])); - } - } - - if (cpi->refresh_last_frame) { - // NOTE(zoeliu): We have two layers of mapping (1) from the per-frame - // reference to the reference frame buffer virtual index; and then (2) from - // the virtual index to the reference frame buffer (RefCntBuffer): - // - // LAST_FRAME, ..., EXTREF_FRAME - // | | - // v v - // remapped_ref_idx[LAST_FRAME - 1], ..., remapped_ref_idx[EXTREF_FRAME - 1] - // | | - // v v - // ref_frame_map[], ..., ref_frame_map[] - // - // When refresh_last_frame is set, it is intended to retire LAST3_FRAME, - // have the other 2 LAST reference frames shifted as follows: - // LAST_FRAME -> LAST2_FRAME -> LAST3_FRAME - // , and then have LAST_FRAME refreshed by the newly coded frame. - // - // To fulfill it, the decoder will be notified to execute following 2 steps: - // - // (a) To change ref_frame_map[] and have the virtual index of LAST3_FRAME - // to point to the newly coded frame, i.e. - // ref_frame_map[lst_fb_idexes[2]] => cur_frame; - // - // (b) To change the 1st layer mapping to have LAST_FRAME mapped to the - // original virtual index of LAST3_FRAME and have the other mappings - // shifted as follows: - // LAST_FRAME, LAST2_FRAME, LAST3_FRAME - // | | | - // v v v - // remapped_ref_idx[2], remapped_ref_idx[0], remapped_ref_idx[1] - assign_frame_buffer_p( - &cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST3_FRAME)], - cm->cur_frame); - - int last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME); - - shift_last_ref_frames(cpi); - cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] = last3_remapped_idx; - - assert(!encode_show_existing_frame(cm)); - memcpy(cpi->interp_filter_selected[LAST_FRAME], - cpi->interp_filter_selected[0], - sizeof(cpi->interp_filter_selected[0])); - - // If the new structure is used, we will always have overlay frames coupled - // with bwdref frames. Therefore, we won't have to perform this update - // in advance (we do this update when the overlay frame shows up). - if (cpi->new_bwdref_update_rule == 0 && cpi->rc.is_last_bipred_frame) { - // Refresh the LAST_FRAME with the BWDREF_FRAME and retire the - // LAST3_FRAME by updating the virtual indices. - // - // NOTE: The source frame for BWDREF does not have a holding position as - // the OVERLAY frame for ALTREF's. Hence, to resolve the reference - // virtual index reshuffling for BWDREF, the encoder always - // specifies a LAST_BIPRED right before BWDREF and completes the - // reshuffling job accordingly. - last3_remapped_idx = get_ref_frame_map_idx(cm, LAST3_FRAME); - - shift_last_ref_frames(cpi); - cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] = - get_ref_frame_map_idx(cm, BWDREF_FRAME); - cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = last3_remapped_idx; - - memcpy(cpi->interp_filter_selected[LAST_FRAME], - cpi->interp_filter_selected[BWDREF_FRAME], - sizeof(cpi->interp_filter_selected[BWDREF_FRAME])); - } - } - -#if DUMP_REF_FRAME_IMAGES == 1 - // Dump out all reference frame images. - dump_ref_frame_images(cpi); -#endif // DUMP_REF_FRAME_IMAGES -} - static void scale_references(AV1_COMP *cpi) { AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); @@ -3750,6 +3366,20 @@ static void scale_references(AV1_COMP *cpi) { } if (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height) { + // Replace the reference buffer with a copy having a thicker border, + // if the reference buffer is higher resolution than the current + // frame, and the border is thin. + if ((ref->y_crop_width > cm->width || + ref->y_crop_height > cm->height) && + ref->border < AOM_BORDER_IN_PIXELS) { + RefCntBuffer *ref_fb = get_ref_frame_buf(cm, ref_frame); + if (aom_yv12_realloc_with_new_border( + &ref_fb->buf, AOM_BORDER_IN_PIXELS, cm->byte_alignment, + num_planes) != 0) { + aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, + "Failed to allocate frame buffer"); + } + } int force_scaling = 0; RefCntBuffer *new_fb = cpi->scaled_ref_buf[ref_frame - 1]; if (new_fb == NULL) { @@ -3767,7 +3397,7 @@ static void scale_references(AV1_COMP *cpi) { if (aom_realloc_frame_buffer( &new_fb->buf, cm->width, cm->height, cm->seq_params.subsampling_x, cm->seq_params.subsampling_y, - cm->seq_params.use_highbitdepth, cpi->oxcf.border_in_pixels, + cm->seq_params.use_highbitdepth, AOM_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL)) { if (force_scaling) { // Release the reference acquired in the get_free_fb() call above. @@ -3830,6 +3460,71 @@ static void set_mv_search_params(AV1_COMP *cpi) { } } +static void set_screen_content_options(AV1_COMP *cpi) { + AV1_COMMON *cm = &cpi->common; + + if (cm->seq_params.force_screen_content_tools != 2) { + cm->allow_screen_content_tools = cm->allow_intrabc = + cm->seq_params.force_screen_content_tools; + return; + } + + if (cpi->oxcf.content == AOM_CONTENT_SCREEN) { + cm->allow_screen_content_tools = cm->allow_intrabc = 1; + return; + } + + // Estimate if the source frame is screen content, based on the portion of + // blocks that have few luma colors. + const uint8_t *src = cpi->source->y_buffer; + assert(src != NULL); + const int use_hbd = cpi->source->flags & YV12_FLAG_HIGHBITDEPTH; + const int stride = cpi->source->y_stride; + const int width = cpi->source->y_width; + const int height = cpi->source->y_height; + const int bd = cm->seq_params.bit_depth; + const int blk_w = 16; + const int blk_h = 16; + // These threshold values are selected experimentally. + const int color_thresh = 4; + const unsigned int var_thresh = 0; + // Counts of blocks with no more than color_thresh colors. + int counts_1 = 0; + // Counts of blocks with no more than color_thresh colors and variance larger + // than var_thresh. + int counts_2 = 0; + + for (int r = 0; r + blk_h <= height; r += blk_h) { + for (int c = 0; c + blk_w <= width; c += blk_w) { + int count_buf[1 << 12]; // Maximum (1 << 12) color levels. + const uint8_t *const this_src = src + r * stride + c; + const int n_colors = + use_hbd ? av1_count_colors_highbd(this_src, stride, blk_w, blk_h, bd, + count_buf) + : av1_count_colors(this_src, stride, blk_w, blk_h, count_buf); + if (n_colors > 1 && n_colors <= color_thresh) { + ++counts_1; + struct buf_2d buf; + buf.stride = stride; + buf.buf = (uint8_t *)this_src; + const unsigned int var = + use_hbd + ? av1_high_get_sby_perpixel_variance(cpi, &buf, BLOCK_16X16, bd) + : av1_get_sby_perpixel_variance(cpi, &buf, BLOCK_16X16); + if (var > var_thresh) ++counts_2; + } + } + } + + // The threshold values are selected experimentally. + cm->allow_screen_content_tools = + counts_1 * blk_h * blk_w * 10 > width * height; + // IntraBC would force loop filters off, so we use more strict rules that also + // requires that the block has high variance. + cm->allow_intrabc = cm->allow_screen_content_tools && + counts_2 * blk_h * blk_w * 15 > width * height; +} + static void set_size_independent_vars(AV1_COMP *cpi) { int i; AV1_COMMON *cm = &cpi->common; @@ -3837,25 +3532,14 @@ static void set_size_independent_vars(AV1_COMP *cpi) { cm->global_motion[i] = default_warp_params; } cpi->global_motion_search_done = 0; + + if (frame_is_intra_only(cm)) set_screen_content_options(cpi); + cpi->is_screen_content_type = (cm->allow_screen_content_tools != 0); + av1_set_speed_features_framesize_independent(cpi, cpi->speed); av1_set_rd_speed_thresholds(cpi); cm->interp_filter = SWITCHABLE; cm->switchable_motion_mode = 1; - - if (frame_is_intra_only(cm)) { - if (cm->seq_params.force_screen_content_tools == 2) { - cm->allow_screen_content_tools = - cpi->oxcf.content == AOM_CONTENT_SCREEN || - is_screen_content(cpi->source->y_buffer, - cpi->source->flags & YV12_FLAG_HIGHBITDEPTH, - cm->seq_params.bit_depth, cpi->source->y_stride, - cpi->source->y_width, cpi->source->y_height); - } else { - cm->allow_screen_content_tools = - cm->seq_params.force_screen_content_tools; - } - } - cpi->is_screen_content_type = (cm->allow_screen_content_tools != 0); } static void set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index, @@ -3885,11 +3569,17 @@ static void set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index, static void init_motion_estimation(AV1_COMP *cpi) { int y_stride = cpi->scaled_source.y_stride; + int y_stride_src = (cpi->oxcf.resize_mode || cpi->oxcf.superres_mode) + ? y_stride + : cpi->lookahead->buf->img.y_stride; if (cpi->sf.mv.search_method == NSTEP) { - av1_init3smotion_compensation(&cpi->ss_cfg, y_stride); + av1_init3smotion_compensation(&cpi->ss_cfg[SS_CFG_SRC], y_stride); + av1_init3smotion_compensation(&cpi->ss_cfg[SS_CFG_LOOKAHEAD], y_stride_src); } else if (cpi->sf.mv.search_method == DIAMOND) { - av1_init_dsmotion_compensation(&cpi->ss_cfg, y_stride); + av1_init_dsmotion_compensation(&cpi->ss_cfg[SS_CFG_SRC], y_stride); + av1_init_dsmotion_compensation(&cpi->ss_cfg[SS_CFG_LOOKAHEAD], + y_stride_src); } } @@ -4143,6 +3833,27 @@ static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { } break; } + case SUPERRES_AUTO: { + // Don't use when screen content tools are used. + if (cpi->common.allow_screen_content_tools) break; + // Don't use for inter frames. + if (!frame_is_intra_only(&cpi->common)) break; + // Don't use for keyframes that can be used as references. + if (cpi->rc.frames_to_key != 1) break; + + // Now decide the use of superres based on 'q'. + int bottom_index, top_index; + const int q = av1_rc_pick_q_and_bounds( + cpi, cpi->oxcf.width, cpi->oxcf.height, &bottom_index, &top_index); + + const int qthresh = 128; + if (q <= qthresh) { + new_denom = SCALE_NUMERATOR; + } else { + new_denom = get_superres_denom_for_qindex(cpi, q); + } + break; + } default: assert(0); } return new_denom; @@ -4254,10 +3965,13 @@ static void setup_frame_size_from_params(AV1_COMP *cpi, } void av1_setup_frame_size(AV1_COMP *cpi) { + AV1_COMMON *cm = &cpi->common; // Reset superres params from previous frame. - cpi->common.superres_scale_denominator = SCALE_NUMERATOR; + cm->superres_scale_denominator = SCALE_NUMERATOR; const size_params_type rsz = calculate_next_size_params(cpi); setup_frame_size_from_params(cpi, &rsz); + + assert(is_min_tile_width_satisfied(cm)); } static void superres_post_encode(AV1_COMP *cpi) { @@ -4306,28 +4020,23 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { assert(IMPLIES(is_lossless_requested(&cpi->oxcf), cm->coded_lossless && cm->all_lossless)); - const int no_loopfilter = cm->coded_lossless || cm->large_scale_tile; - const int no_cdef = - !cm->seq_params.enable_cdef || cm->coded_lossless || cm->large_scale_tile; - const int no_restoration = !cm->seq_params.enable_restoration || - cm->all_lossless || cm->large_scale_tile; + const int use_loopfilter = !cm->coded_lossless && !cm->large_scale_tile; + const int use_cdef = cm->seq_params.enable_cdef && !cm->coded_lossless && + !cm->large_scale_tile; + const int use_restoration = cm->seq_params.enable_restoration && + !cm->all_lossless && !cm->large_scale_tile; struct loopfilter *lf = &cm->lf; - if (no_loopfilter) { +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, loop_filter_time); +#endif + if (use_loopfilter) { + aom_clear_system_state(); + av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick); + } else { lf->filter_level[0] = 0; lf->filter_level[1] = 0; - } else { - struct aom_usec_timer timer; - - aom_clear_system_state(); - - aom_usec_timer_start(&timer); - - av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick); - - aom_usec_timer_mark(&timer); - cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer); } if (lf->filter_level[0] || lf->filter_level[1]) { @@ -4345,31 +4054,39 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { #endif 0, num_planes, 0); } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, loop_filter_time); +#endif - if (!no_restoration) + if (use_restoration) av1_loop_restoration_save_boundary_lines(&cm->cur_frame->buf, cm, 0); - if (no_cdef) { - cm->cdef_info.cdef_bits = 0; - cm->cdef_info.cdef_strengths[0] = 0; - cm->cdef_info.nb_cdef_strengths = 1; - cm->cdef_info.cdef_uv_strengths[0] = 0; - } else { + if (use_cdef) { +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, cdef_time); +#endif // Find CDEF parameters av1_cdef_search(&cm->cur_frame->buf, cpi->source, cm, xd, cpi->sf.fast_cdef_search); // Apply the filter av1_cdef_frame(&cm->cur_frame->buf, cm, xd); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, cdef_time); +#endif + } else { + cm->cdef_info.cdef_bits = 0; + cm->cdef_info.cdef_strengths[0] = 0; + cm->cdef_info.nb_cdef_strengths = 1; + cm->cdef_info.cdef_uv_strengths[0] = 0; } superres_post_encode(cpi); - if (no_restoration) { - cm->rst_info[0].frame_restoration_type = RESTORE_NONE; - cm->rst_info[1].frame_restoration_type = RESTORE_NONE; - cm->rst_info[2].frame_restoration_type = RESTORE_NONE; - } else { +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, loop_restoration_time); +#endif + if (use_restoration) { av1_loop_restoration_save_boundary_lines(&cm->cur_frame->buf, cm, 1); av1_pick_filter_restoration(cpi->source, cpi); if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE || @@ -4383,61 +4100,14 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { av1_loop_restoration_filter_frame(&cm->cur_frame->buf, cm, 0, &cpi->lr_ctxt); } - } -} - -static int get_refresh_frame_flags(const AV1_COMP *const cpi) { - const AV1_COMMON *const cm = &cpi->common; - - // Switch frames and shown key-frames overwrite all reference slots - if ((cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) || - frame_is_sframe(cm)) - return 0xFF; - - int refresh_mask = 0; - - // NOTE(zoeliu): When LAST_FRAME is to get refreshed, the decoder will be - // notified to get LAST3_FRAME refreshed and then the virtual indexes for all - // the 3 LAST reference frames will be updated accordingly, i.e.: - // (1) The original virtual index for LAST3_FRAME will become the new virtual - // index for LAST_FRAME; and - // (2) The original virtual indexes for LAST_FRAME and LAST2_FRAME will be - // shifted and become the new virtual indexes for LAST2_FRAME and - // LAST3_FRAME. - refresh_mask |= - (cpi->refresh_last_frame << get_ref_frame_map_idx(cm, LAST3_FRAME)); - - const int bwd_ref_frame = - (cpi->new_bwdref_update_rule == 1) ? EXTREF_FRAME : BWDREF_FRAME; - refresh_mask |= - (cpi->refresh_bwd_ref_frame << get_ref_frame_map_idx(cm, bwd_ref_frame)); - - refresh_mask |= - (cpi->refresh_alt2_ref_frame << get_ref_frame_map_idx(cm, ALTREF2_FRAME)); - - if (av1_preserve_existing_gf(cpi)) { - // We have decided to preserve the previously existing golden frame as our - // new ARF frame. However, in the short term we leave it in the GF slot and, - // if we're updating the GF with the current decoded frame, we save it - // instead to the ARF slot. - // Later, in the function av1_encoder.c:av1_update_reference_frames() we - // will swap gld_fb_idx and alt_fb_idx to achieve our objective. We do it - // there so that it can be done outside of the recode loop. - // Note: This is highly specific to the use of ARF as a forward reference, - // and this needs to be generalized as other uses are implemented - // (like RTC/temporal scalability). - - if (!cpi->preserve_arf_as_gld) { - refresh_mask |= (cpi->refresh_golden_frame - << get_ref_frame_map_idx(cm, ALTREF_FRAME)); - } } else { - refresh_mask |= - (cpi->refresh_golden_frame << get_ref_frame_map_idx(cm, GOLDEN_FRAME)); - refresh_mask |= - (cpi->refresh_alt_ref_frame << get_ref_frame_map_idx(cm, ALTREF_FRAME)); + cm->rst_info[0].frame_restoration_type = RESTORE_NONE; + cm->rst_info[1].frame_restoration_type = RESTORE_NONE; + cm->rst_info[2].frame_restoration_type = RESTORE_NONE; } - return refresh_mask; +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, loop_restoration_time); +#endif } static void fix_interp_filter(InterpFilter *const interp_filter, @@ -4467,10 +4137,6 @@ static void finalize_encoded_frame(AV1_COMP *const cpi) { AV1_COMMON *const cm = &cpi->common; CurrentFrame *const current_frame = &cm->current_frame; - // This bitfield indicates which reference frame slots will be overwritten by - // the current frame - current_frame->refresh_frame_flags = get_refresh_frame_flags(cpi); - if (!cm->seq_params.reduced_still_picture_hdr && encode_show_existing_frame(cm)) { RefCntBuffer *const frame_to_show = @@ -4512,6 +4178,47 @@ static void finalize_encoded_frame(AV1_COMP *const cpi) { fix_interp_filter(&cm->interp_filter, cpi->td.counts); } +static int get_regulated_q_overshoot(AV1_COMP *const cpi, int q_low, int q_high, + int top_index, int bottom_index) { + const AV1_COMMON *const cm = &cpi->common; + const RATE_CONTROL *const rc = &cpi->rc; + + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); + + int q_regulated = + av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, + AOMMAX(q_high, top_index), cm->width, cm->height); + + int retries = 0; + while (q_regulated < q_low && retries < 10) { + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); + q_regulated = + av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, + AOMMAX(q_high, top_index), cm->width, cm->height); + retries++; + } + return q_regulated; +} + +static int get_regulated_q_undershoot(AV1_COMP *const cpi, int q_high, + int top_index, int bottom_index) { + const AV1_COMMON *const cm = &cpi->common; + const RATE_CONTROL *const rc = &cpi->rc; + + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); + int q_regulated = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, + top_index, cm->width, cm->height); + + int retries = 0; + while (q_regulated > q_high && retries < 10) { + av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); + q_regulated = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, + top_index, cm->width, cm->height); + retries++; + } + return q_regulated; +} + // Called after encode_with_recode_loop() has just encoded a frame and packed // its bitstream. This function works out whether we under- or over-shot // our bitrate target and adjusts q as appropriate. Also decides whether @@ -4582,7 +4289,6 @@ static void recode_loop_update_q(AV1_COMP *const cpi, int *const loop, // Is the projected frame size out of range and are we allowed // to attempt to recode. int last_q = *q; - int retries = 0; // Frame size out of permitted range: // Update correction factor & compute new Q to try... @@ -4595,26 +4301,21 @@ static void recode_loop_update_q(AV1_COMP *const cpi, int *const loop, // Raise Qlow as to at least the current value *q_low = *q < *q_high ? *q + 1 : *q_high; - if (*undershoot_seen || loop_at_this_size > 1) { - // Update rate_correction_factor unless + if (*undershoot_seen || loop_at_this_size > 2 || + (loop_at_this_size == 2 && !frame_is_intra_only(cm))) { av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); *q = (*q_high + *q_low + 1) / 2; + } else if (loop_at_this_size == 2 && frame_is_intra_only(cm)) { + const int q_mid = (*q_high + *q_low + 1) / 2; + const int q_regulated = get_regulated_q_overshoot( + cpi, *q_low, *q_high, top_index, bottom_index); + // Get 'q' in-between 'q_mid' and 'q_regulated' for a smooth + // transition between loop_at_this_size < 2 and loop_at_this_size > 2. + *q = (q_mid + q_regulated + 1) / 2; } else { - // Update rate_correction_factor unless - av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); - - *q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - AOMMAX(*q_high, top_index), cm->width, - cm->height); - - while (*q < *q_low && retries < 10) { - av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); - *q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - AOMMAX(*q_high, top_index), cm->width, - cm->height); - retries++; - } + *q = get_regulated_q_overshoot(cpi, *q_low, *q_high, top_index, + bottom_index); } *overshoot_seen = 1; @@ -4622,13 +4323,28 @@ static void recode_loop_update_q(AV1_COMP *const cpi, int *const loop, // Frame is too small *q_high = *q > *q_low ? *q - 1 : *q_low; - if (*overshoot_seen || loop_at_this_size > 1) { + if (*overshoot_seen || loop_at_this_size > 2 || + (loop_at_this_size == 2 && !frame_is_intra_only(cm))) { av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); *q = (*q_high + *q_low) / 2; + } else if (loop_at_this_size == 2 && frame_is_intra_only(cm)) { + const int q_mid = (*q_high + *q_low) / 2; + const int q_regulated = + get_regulated_q_undershoot(cpi, *q_high, top_index, bottom_index); + // Get 'q' in-between 'q_mid' and 'q_regulated' for a smooth + // transition between loop_at_this_size < 2 and loop_at_this_size > 2. + *q = (q_mid + q_regulated) / 2; + + // Special case reset for qlow for constrained quality. + // This should only trigger where there is very substantial + // undershoot on a frame and the auto cq level is above + // the user passsed in value. + if (cpi->oxcf.rc_mode == AOM_CQ && q_regulated < *q_low) { + *q_low = *q; + } } else { - av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); - *q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - top_index, cm->width, cm->height); + *q = get_regulated_q_undershoot(cpi, *q_high, top_index, bottom_index); + // Special case reset for qlow for constrained quality. // This should only trigger where there is very substantial // undershoot on a frame and the auto cq level is above @@ -4636,13 +4352,6 @@ static void recode_loop_update_q(AV1_COMP *const cpi, int *const loop, if (cpi->oxcf.rc_mode == AOM_CQ && *q < *q_low) { *q_low = *q; } - - while (*q > *q_high && retries < 10) { - av1_rc_update_rate_correction_factors(cpi, cm->width, cm->height); - *q = av1_rc_regulate_q(cpi, rc->this_frame_target, bottom_index, - top_index, cm->width, cm->height); - retries++; - } } *undershoot_seen = 1; @@ -4680,6 +4389,10 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { int loop = 0; int overshoot_seen = 0; int undershoot_seen = 0; + +#if CONFIG_COLLECT_COMPONENT_TIMING + printf("\n Encoding a frame:"); +#endif do { aom_clear_system_state(); @@ -4706,6 +4419,9 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { } av1_set_quantizer(cm, q); av1_init_quantizer(cpi); + + av1_set_variance_partition_thresholds(cpi, q, 0); + // printf("Frame %d/%d: q = %d, frame_type = %d superres_denom = %d\n", // cm->current_frame.frame_number, cm->show_frame, q, // cm->current_frame.frame_type, cm->superres_scale_denominator); @@ -4741,17 +4457,14 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { segfeatures_copy(&cm->cur_frame->seg, &cm->seg); if (allow_recode) save_coding_context(cpi); - +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, av1_encode_frame_time); +#endif // transform / motion compensation build reconstruction frame av1_encode_frame(cpi); - - // Update some stats from cyclic refresh, and check if we should not update - // golden reference, for 1 pass CBR. - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && - cm->current_frame.frame_type != KEY_FRAME && - (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == AOM_CBR)) { - av1_cyclic_refresh_check_golden_update(cpi); - } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, av1_encode_frame_time); +#endif aom_clear_system_state(); @@ -4795,6 +4508,9 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { ++cpi->tot_recode_hits; #endif } +#if CONFIG_COLLECT_COMPONENT_TIMING + if (loop) printf("\n Recoding:"); +#endif } while (loop); return AOM_CODEC_OK; @@ -4831,10 +4547,8 @@ static void dump_filtered_recon_frames(AV1_COMP *cpi) { for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame); const int ref_offset = buf != NULL ? (int)buf->order_hint : -1; - printf(" %d(%c-%d-%4.2f)", ref_offset, - (cpi->ref_frame_flags & flag_list[ref_frame]) ? 'Y' : 'N', - buf ? (int)buf->frame_rf_level : -1, - buf ? rate_factor_deltas[buf->frame_rf_level] : -1); + printf(" %d(%c)", ref_offset, + (cpi->ref_frame_flags & flag_list[ref_frame]) ? 'Y' : 'N'); } printf(" ]\n"); @@ -4862,13 +4576,12 @@ static void dump_filtered_recon_frames(AV1_COMP *cpi) { printf( "\nFrame=%5d, encode_update_type[%5d]=%1d, frame_offset=%d, " "show_frame=%d, show_existing_frame=%d, source_alt_ref_active=%d, " - "refresh_alt_ref_frame=%d, rf_level=%d, " + "refresh_alt_ref_frame=%d, " "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n\n", current_frame->frame_number, cpi->twopass.gf_group.index, cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index], current_frame->order_hint, cm->show_frame, cm->show_existing_frame, cpi->rc.source_alt_ref_active, cpi->refresh_alt_ref_frame, - cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index], recon_buf->y_stride, recon_buf->uv_stride, cm->width, cm->height); #if 0 int ref_frame; @@ -4898,32 +4611,45 @@ static void dump_filtered_recon_frames(AV1_COMP *cpi) { } #endif // DUMP_RECON_FRAMES -static int setup_interp_filter_search_mask(AV1_COMP *cpi) { - InterpFilters ifilter; - int ref_total[REF_FRAMES] = { 0 }; - MV_REFERENCE_FRAME ref; - int mask = 0; - int arf_idx = ALTREF_FRAME; - if (cpi->common.last_frame_type == KEY_FRAME || cpi->refresh_alt_ref_frame) - return mask; - for (ref = LAST_FRAME; ref <= ALTREF_FRAME; ++ref) - for (ifilter = EIGHTTAP_REGULAR; ifilter <= MULTITAP_SHARP; ++ifilter) - ref_total[ref] += cpi->interp_filter_selected[ref][ifilter]; +static int get_interp_filter_selected(const AV1_COMMON *const cm, + MV_REFERENCE_FRAME ref, + InterpFilters ifilter) { + const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref); + if (buf == NULL) return 0; + return buf->interp_filter_selected[ifilter]; +} - for (ifilter = EIGHTTAP_REGULAR; ifilter <= MULTITAP_SHARP; ++ifilter) { - if ((ref_total[LAST_FRAME] && - cpi->interp_filter_selected[LAST_FRAME][ifilter] * 30 <= - ref_total[LAST_FRAME]) && - (((cpi->interp_filter_selected[LAST2_FRAME][ifilter] * 20) + - (cpi->interp_filter_selected[LAST3_FRAME][ifilter] * 20) + - (cpi->interp_filter_selected[GOLDEN_FRAME][ifilter] * 20) + - (cpi->interp_filter_selected[BWDREF_FRAME][ifilter] * 10) + - (cpi->interp_filter_selected[ALTREF2_FRAME][ifilter] * 10) + - (cpi->interp_filter_selected[arf_idx][ifilter] * 10)) < - (ref_total[LAST2_FRAME] + ref_total[LAST3_FRAME] + - ref_total[GOLDEN_FRAME] + ref_total[BWDREF_FRAME] + - ref_total[ALTREF2_FRAME] + ref_total[ALTREF_FRAME]))) - mask |= 1 << ifilter; +static int setup_interp_filter_search_mask(AV1_COMP *cpi) { + const AV1_COMMON *const cm = &cpi->common; + int ref_total[REF_FRAMES] = { 0 }; + + if (cpi->common.last_frame_type == KEY_FRAME || cpi->refresh_alt_ref_frame) + return 0; + + for (MV_REFERENCE_FRAME ref = LAST_FRAME; ref <= ALTREF_FRAME; ++ref) { + for (InterpFilters ifilter = EIGHTTAP_REGULAR; ifilter <= MULTITAP_SHARP; + ++ifilter) { + ref_total[ref] += get_interp_filter_selected(cm, ref, ifilter); + } + } + int ref_total_total = (ref_total[LAST2_FRAME] + ref_total[LAST3_FRAME] + + ref_total[GOLDEN_FRAME] + ref_total[BWDREF_FRAME] + + ref_total[ALTREF2_FRAME] + ref_total[ALTREF_FRAME]); + + int mask = 0; + for (InterpFilters ifilter = EIGHTTAP_REGULAR; ifilter <= MULTITAP_SHARP; + ++ifilter) { + int last_score = get_interp_filter_selected(cm, LAST_FRAME, ifilter) * 30; + if (ref_total[LAST_FRAME] && last_score <= ref_total[LAST_FRAME]) { + int filter_score = + get_interp_filter_selected(cm, LAST2_FRAME, ifilter) * 20 + + get_interp_filter_selected(cm, LAST3_FRAME, ifilter) * 20 + + get_interp_filter_selected(cm, GOLDEN_FRAME, ifilter) * 20 + + get_interp_filter_selected(cm, BWDREF_FRAME, ifilter) * 10 + + get_interp_filter_selected(cm, ALTREF2_FRAME, ifilter) * 10 + + get_interp_filter_selected(cm, ALTREF_FRAME, ifilter) * 10; + if (filter_score < ref_total_total) mask |= 1 << ifilter; + } } return mask; } @@ -5061,14 +4787,30 @@ static int is_integer_mv(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *cur_picture, return 0; } -static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, - unsigned int *frame_flags) { +// Refresh reference frame buffers according to refresh_frame_flags. +static void refresh_reference_frames(AV1_COMP *cpi) { + AV1_COMMON *const cm = &cpi->common; + // All buffers are refreshed for shown keyframes and S-frames. + + for (int ref_frame = 0; ref_frame < REF_FRAMES; ref_frame++) { + if (((cm->current_frame.refresh_frame_flags >> ref_frame) & 1) == 1) { + assign_frame_buffer_p(&cm->ref_frame_map[ref_frame], cm->cur_frame); + } + } +} + +static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, + uint8_t *dest) { AV1_COMMON *const cm = &cpi->common; SequenceHeader *const seq_params = &cm->seq_params; CurrentFrame *const current_frame = &cm->current_frame; const AV1EncoderConfig *const oxcf = &cpi->oxcf; struct segmentation *const seg = &cm->seg; +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, encode_frame_to_data_rate_time); +#endif + // frame type has been decided outside of this function call cm->cur_frame->frame_type = current_frame->frame_type; @@ -5088,11 +4830,10 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, if (cpi->oxcf.pass == 2 && cpi->sf.adaptive_interp_filter_search) cpi->sf.interp_filter_search_mask = setup_interp_filter_search_mask(cpi); - if (encode_show_existing_frame(cm)) { - // NOTE(zoeliu): In BIDIR_PRED, the existing frame to show is the current - // BWDREF_FRAME in the reference frame buffer. - cpi->frame_flags = *frame_flags; + cpi->two_pass_partition_search = cpi->sf.two_pass_partition_search && + !cpi->partition_search_skippable_frame; + if (encode_show_existing_frame(cm)) { restore_coding_context(cpi); finalize_encoded_frame(cpi); @@ -5116,26 +4857,11 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, dump_filtered_recon_frames(cpi); #endif // DUMP_RECON_FRAMES - // Update the LAST_FRAME in the reference frame buffer. - // NOTE: - // (1) For BWDREF_FRAME as the show_existing_frame, the reference frame - // update has been done previously when handling the LAST_BIPRED_FRAME - // right before BWDREF_FRAME (in the display order); - // (2) For INTNL_OVERLAY as the show_existing_frame, the reference frame - // update will be done when the following is called, which will - // exchange - // the virtual indexes between LAST_FRAME and ALTREF2_FRAME, so that - // LAST3 will get retired, LAST2 becomes LAST3, LAST becomes LAST2, - // and - // ALTREF2_FRAME will serve as the new LAST_FRAME. - update_reference_frames(cpi); + // NOTE: Save the new show frame buffer index for --test-code=warn, i.e., + // for the purpose to verify no mismatch between encoder and decoder. + if (cm->show_frame) cpi->last_show_frame_buf = cm->cur_frame; - // Update frame flags - cpi->frame_flags &= ~FRAMEFLAGS_GOLDEN; - cpi->frame_flags &= ~FRAMEFLAGS_BWDREF; - cpi->frame_flags &= ~FRAMEFLAGS_ALTREF; - - *frame_flags = cpi->frame_flags & ~FRAMEFLAGS_KEY; + refresh_reference_frames(cpi); // Since we allocate a spot for the OVERLAY frame in the gf group, we need // to do post-encoding update accordingly. @@ -5260,8 +4986,14 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, } cm->timing_info_present &= !seq_params->reduced_still_picture_hdr; +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, encode_with_recode_loop_time); +#endif if (encode_with_recode_loop(cpi, size, dest) != AOM_CODEC_OK) return AOM_CODEC_ERROR; +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, encode_with_recode_loop_time); +#endif #ifdef OUTPUT_YUV_SKINMAP if (cpi->common.current_frame.frame_number > 1) { @@ -5280,12 +5012,6 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, } } - // If the encoder forced a KEY_FRAME decision or if frame is an S_FRAME - if ((current_frame->frame_type == KEY_FRAME && cm->show_frame) || - frame_is_sframe(cm)) { - cpi->refresh_last_frame = 1; - } - cm->cur_frame->buf.color_primaries = seq_params->color_primaries; cm->cur_frame->buf.transfer_characteristics = seq_params->transfer_characteristics; @@ -5326,8 +5052,14 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, finalize_encoded_frame(cpi); // Build the bitstream int largest_tile_id = 0; // Output from pack_bitstream +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, av1_pack_bitstream_final_time); +#endif if (av1_pack_bitstream(cpi, dest, size, &largest_tile_id) != AOM_CODEC_OK) return AOM_CODEC_ERROR; +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, av1_pack_bitstream_final_time); +#endif cpi->seq_params_locked = 1; @@ -5358,7 +5090,11 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, release_scaled_references(cpi); } - update_reference_frames(cpi); + // NOTE: Save the new show frame buffer index for --test-code=warn, i.e., + // for the purpose to verify no mismatch between encoder and decoder. + if (cm->show_frame) cpi->last_show_frame_buf = cm->cur_frame; + + refresh_reference_frames(cpi); #if CONFIG_ENTROPY_STATS av1_accumulate_frame_counts(&aggregate_fc, &cpi->counts); @@ -5384,31 +5120,27 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest, #endif // EXT_TILE_DEBUG #undef EXT_TILE_DEBUG - if (cpi->refresh_golden_frame == 1) - cpi->frame_flags |= FRAMEFLAGS_GOLDEN; - else - cpi->frame_flags &= ~FRAMEFLAGS_GOLDEN; +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, encode_frame_to_data_rate_time); - if (cpi->refresh_alt_ref_frame == 1) - cpi->frame_flags |= FRAMEFLAGS_ALTREF; - else - cpi->frame_flags &= ~FRAMEFLAGS_ALTREF; + // Print out timing information. + int i; + fprintf(stderr, "\n Frame number: %d, Frame type: %s, Show Frame: %d\n", + cm->current_frame.frame_number, + get_frame_type_enum(cm->current_frame.frame_type), cm->show_frame); + for (i = 0; i < kTimingComponents; i++) { + cpi->component_time[i] += cpi->frame_component_time[i]; + fprintf(stderr, " %s: %" PRId64 " us (total: %" PRId64 " us)\n", + get_component_name(i), cpi->frame_component_time[i], + cpi->component_time[i]); + cpi->frame_component_time[i] = 0; + } +#endif - if (cpi->refresh_bwd_ref_frame == 1) - cpi->frame_flags |= FRAMEFLAGS_BWDREF; - else - cpi->frame_flags &= ~FRAMEFLAGS_BWDREF; cm->last_frame_type = current_frame->frame_type; av1_rc_postencode_update(cpi, *size); - if (current_frame->frame_type == KEY_FRAME) { - // Tell the caller that the frame was coded as a key frame - *frame_flags = cpi->frame_flags | FRAMEFLAGS_KEY; - } else { - *frame_flags = cpi->frame_flags & ~FRAMEFLAGS_KEY; - } - // Store encoded frame's hash table for is_integer_mv() next time if (oxcf->pass != 1 && cpi->common.allow_screen_content_tools) { cpi->previous_hash_table = &cm->cur_frame->hash_table; @@ -5449,12 +5181,24 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, cpi->source = frame_input->source; cpi->unscaled_last_source = frame_input->last_source; + current_frame->refresh_frame_flags = frame_params->refresh_frame_flags; cm->error_resilient_mode = frame_params->error_resilient_mode; cm->primary_ref_frame = frame_params->primary_ref_frame; cm->current_frame.frame_type = frame_params->frame_type; cm->show_frame = frame_params->show_frame; cpi->ref_frame_flags = frame_params->ref_frame_flags; cpi->speed = frame_params->speed; + cm->show_existing_frame = frame_params->show_existing_frame; + cpi->existing_fb_idx_to_show = frame_params->existing_fb_idx_to_show; + + memcpy(cm->remapped_ref_idx, frame_params->remapped_ref_idx, + REF_FRAMES * sizeof(*cm->remapped_ref_idx)); + + cpi->refresh_last_frame = frame_params->refresh_last_frame; + cpi->refresh_golden_frame = frame_params->refresh_golden_frame; + cpi->refresh_bwd_ref_frame = frame_params->refresh_bwd_ref_frame; + cpi->refresh_alt2_ref_frame = frame_params->refresh_alt2_ref_frame; + cpi->refresh_alt_ref_frame = frame_params->refresh_alt_ref_frame; if (current_frame->frame_type == KEY_FRAME && cm->show_frame) current_frame->frame_number = 0; @@ -5471,8 +5215,8 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, if (cpi->oxcf.pass == 1) { av1_first_pass(cpi, frame_input->ts_duration); } else if (cpi->oxcf.pass == 0 || cpi->oxcf.pass == 2) { - if (encode_frame_to_data_rate(cpi, &frame_results->size, dest, - frame_params->frame_flags) != AOM_CODEC_OK) { + if (encode_frame_to_data_rate(cpi, &frame_results->size, dest) != + AOM_CODEC_OK) { return AOM_CODEC_ERROR; } } else { @@ -5521,7 +5265,6 @@ int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, int64_t end_time) { AV1_COMMON *const cm = &cpi->common; const SequenceHeader *const seq_params = &cm->seq_params; - struct aom_usec_timer timer; int res = 0; const int subsampling_x = sd->subsampling_x; const int subsampling_y = sd->subsampling_y; @@ -5529,8 +5272,10 @@ int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, check_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y); +#if CONFIG_INTERNAL_STATS + struct aom_usec_timer timer; aom_usec_timer_start(&timer); - +#endif #if CONFIG_DENOISE if (cpi->oxcf.noise_level > 0) if (apply_denoise_2d(cpi, sd, cpi->oxcf.noise_block_size, @@ -5541,9 +5286,10 @@ int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, if (av1_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, use_highbitdepth, frame_flags)) res = -1; +#if CONFIG_INTERNAL_STATS aom_usec_timer_mark(&timer); cpi->time_receive_data += aom_usec_timer_elapsed(&timer); - +#endif if ((seq_params->profile == PROFILE_0) && !seq_params->monochrome && (subsampling_x != 1 || subsampling_y != 1)) { aom_internal_error(&cm->error, AOM_CODEC_INVALID_PARAM, @@ -5673,40 +5419,18 @@ static void compute_internal_stats(AV1_COMP *cpi, int frame_bytes) { } } #endif // CONFIG_INTERNAL_STATS - -// Don't allow a show_existing_frame to coincide with an error resilient or -// S-Frame. An exception can be made in the case of a keyframe, since it does -// not depend on any previous frames. -static int allow_show_existing(const AV1_COMP *const cpi) { - if (cpi->common.current_frame.frame_number == 0) return 0; - - const struct lookahead_entry *lookahead_src = - av1_lookahead_peek(cpi->lookahead, 0); - if (lookahead_src == NULL) return 1; - - const int is_error_resilient = - cpi->oxcf.error_resilient_mode || - (lookahead_src->flags & AOM_EFLAG_ERROR_RESILIENT); - const int is_s_frame = - cpi->oxcf.s_frame_mode || (lookahead_src->flags & AOM_EFLAG_SET_S_FRAME); - const int is_key_frame = - (cpi->rc.frames_to_key == 0) || (cpi->frame_flags & FRAMEFLAGS_KEY); - return !(is_error_resilient || is_s_frame) || is_key_frame; -} - int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, size_t *size, uint8_t *dest, int64_t *time_stamp, int64_t *time_end, int flush, const aom_rational_t *timebase) { const AV1EncoderConfig *const oxcf = &cpi->oxcf; AV1_COMMON *const cm = &cpi->common; - struct aom_usec_timer cmptimer; #if CONFIG_BITSTREAM_DEBUG assert(cpi->oxcf.max_threads == 0 && "bitstream debug tool does not support multithreading"); bitstream_queue_record_write(); - bitstream_queue_set_frame_write(current_frame->frame_number * 2 + + bitstream_queue_set_frame_write(cm->current_frame.frame_number * 2 + cm->show_frame); #endif @@ -5716,8 +5440,10 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, cm->showable_frame = 0; *size = 0; +#if CONFIG_INTERNAL_STATS + struct aom_usec_timer cmptimer; aom_usec_timer_start(&cmptimer); - +#endif set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV, 0); // Normal defaults @@ -5727,14 +5453,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, if (oxcf->large_scale_tile) cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; - // default reference buffers update config - av1_configure_buffer_updates(cpi, LF_UPDATE); - // Initialize fields related to forward keyframes cpi->no_show_kf = 0; - cm->show_existing_frame &= allow_show_existing(cpi); - if (assign_cur_frame_new_fb(cm) == NULL) return AOM_CODEC_ERROR; const int result = av1_encode_strategy(cpi, size, dest, frame_flags, @@ -5745,15 +5466,17 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, // Returning -1 indicates no frame encoded; more input is required return -1; } - +#if CONFIG_INTERNAL_STATS aom_usec_timer_mark(&cmptimer); cpi->time_compress_data += aom_usec_timer_elapsed(&cmptimer); - +#endif if (cpi->b_calculate_psnr) { if (cm->show_existing_frame || (oxcf->pass != 1 && cm->show_frame)) { generate_psnr_packet(cpi); } } + if (cpi->keep_level_stats && oxcf->pass != 1) + av1_update_level_info(cpi, *size, *time_stamp, *time_end); #if CONFIG_INTERNAL_STATS if (oxcf->pass != 1) { @@ -5954,6 +5677,8 @@ void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) { cpi->ext_refresh_bwd_ref_frame = (upd & AOM_BWD_FLAG) != 0; cpi->ext_refresh_alt2_ref_frame = (upd & AOM_ALT2_FLAG) != 0; cpi->ext_refresh_frame_flags_pending = 1; + } else { + cpi->ext_refresh_frame_flags_pending = 0; } cpi->ext_use_ref_frame_mvs = cpi->oxcf.allow_ref_frame_mvs & @@ -5985,7 +5710,7 @@ aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi) { if (payload_offset + sequence_header_size > sizeof(header_buf)) return NULL; memmove(&header_buf[payload_offset], &header_buf[0], sequence_header_size); - if (write_obu_header(OBU_SEQUENCE_HEADER, 0, &header_buf[0]) != + if (av1_write_obu_header(cpi, OBU_SEQUENCE_HEADER, 0, &header_buf[0]) != obu_header_size) { return NULL; } diff --git a/third_party/aom/av1/encoder/encoder.h b/third_party/aom/av1/encoder/encoder.h index dec531fa88..bf02394a5e 100644 --- a/third_party/aom/av1/encoder/encoder.h +++ b/third_party/aom/av1/encoder/encoder.h @@ -12,6 +12,7 @@ #ifndef AOM_AV1_ENCODER_ENCODER_H_ #define AOM_AV1_ENCODER_ENCODER_H_ +#include #include #include "config/aom_config.h" @@ -24,11 +25,14 @@ #include "av1/common/onyxc_int.h" #include "av1/common/resize.h" #include "av1/common/timing.h" +#include "av1/common/blockd.h" +#include "av1/common/enums.h" #include "av1/encoder/aq_cyclicrefresh.h" #include "av1/encoder/av1_quantize.h" #include "av1/encoder/context_tree.h" #include "av1/encoder/encodemb.h" #include "av1/encoder/firstpass.h" +#include "av1/encoder/level.h" #include "av1/encoder/lookahead.h" #include "av1/encoder/mbgraph.h" #include "av1/encoder/mcomp.h" @@ -36,6 +40,7 @@ #include "av1/encoder/rd.h" #include "av1/encoder/speed_features.h" #include "av1/encoder/tokenize.h" +#include "av1/encoder/block.h" #if CONFIG_INTERNAL_STATS #include "aom_dsp/ssim.h" @@ -60,18 +65,12 @@ typedef struct { } CODING_CONTEXT; enum { - // regular inter frame - REGULAR_FRAME = 0, - // alternate reference frame - ARF_FRAME = 1, - // overlay frame - OVERLAY_FRAME = 2, - // golden frame - GLD_FRAME = 3, - // backward reference frame - BRF_FRAME = 4, - // extra alternate reference frame - EXT_ARF_FRAME = 5, + REGULAR_FRAME, // regular inter frame + ARF_FRAME, // alternate reference frame + OVERLAY_FRAME, // overlay frame + GLD_FRAME, // golden frame + BRF_FRAME, // backward reference frame + INTERNAL_ARF_FRAME, // internal alternate reference frame FRAME_CONTEXT_INDEXES } UENUM1BYTE(FRAME_CONTEXT_INDEX); @@ -85,7 +84,10 @@ enum { enum { // Good Quality Fast Encoding. The encoder balances quality with the amount of // time it takes to encode the output. Speed setting controls how fast. - GOOD + GOOD, + // Realtime Fast Encoding. Will force some restrictions on bitrate + // constraints. + REALTIME } UENUM1BYTE(MODE); enum { @@ -121,22 +123,38 @@ enum { } UENUM1BYTE(RESIZE_MODE); enum { - SUPERRES_NONE = 0, // No frame superres allowed - SUPERRES_FIXED = 1, // All frames are coded at the specified scale, - // and super-resolved. - SUPERRES_RANDOM = 2, // All frames are coded at a random scale, - // and super-resolved. - SUPERRES_QTHRESH = 3, // Superres scale for a frame is determined based on - // q_index + SUPERRES_NONE, // No frame superres allowed. + SUPERRES_FIXED, // All frames are coded at the specified scale, + // and super-resolved. + SUPERRES_RANDOM, // All frames are coded at a random scale, + // and super-resolved. + SUPERRES_QTHRESH, // Superres scale for a frame is determined based on + // q_index. + SUPERRES_AUTO, // Automatically select superres for appropriate frames. SUPERRES_MODES } UENUM1BYTE(SUPERRES_MODE); +typedef enum { + kInvalid = 0, + kLowSadLowSumdiff = 1, + kLowSadHighSumdiff = 2, + kHighSadLowSumdiff = 3, + kHighSadHighSumdiff = 4, + kLowVarHighSumdiff = 5, + kVeryHighSad = 6, +} CONTENT_STATE_SB; + +enum { + SS_CFG_SRC = 0, + SS_CFG_LOOKAHEAD = 1, + SS_CFG_TOTAL = 2 +} UENUM1BYTE(SS_CFG_OFFSET); + typedef struct TplDepStats { int64_t intra_cost; int64_t inter_cost; int64_t mc_flow; int64_t mc_dep_cost; - int64_t mc_ref_cost; int ref_frame_index; int_mv mv; @@ -153,6 +171,12 @@ typedef struct TplDepFrame { int base_qindex; } TplDepFrame; +typedef enum { + COST_UPD_SB, + COST_UPD_SBROW, + COST_UPD_TILE, +} COST_UPDATE_TYPE; + #define TPL_DEP_COST_SCALE_LOG2 4 typedef struct AV1EncoderConfig { @@ -291,10 +315,6 @@ typedef struct AV1EncoderConfig { aom_fixed_buf_t two_pass_stats_in; -#if CONFIG_FP_MB_STATS - aom_fixed_buf_t firstpass_mb_stats_in; -#endif - aom_tune_metric tuning; aom_tune_content content; int use_highbitdepth; @@ -324,14 +344,22 @@ typedef struct AV1EncoderConfig { unsigned int motion_vector_unit_test; const cfg_options_t *cfg; int enable_rect_partitions; + int enable_ab_partitions; + int enable_1to4_partitions; + int min_partition_size; + int max_partition_size; int enable_intra_edge_filter; int enable_tx64; + int tx_size_search_method; + int enable_flip_idtx; int enable_order_hint; int enable_dist_wtd_comp; int enable_ref_frame_mvs; unsigned int max_reference_frames; + int enable_reduced_reference_set; unsigned int allow_ref_frame_mvs; int enable_masked_comp; + int enable_onesided_comp; int enable_interintra_comp; int enable_smooth_interintra; int enable_diff_wtd_comp; @@ -360,8 +388,15 @@ typedef struct AV1EncoderConfig { int reduced_tx_type_set; int use_intra_dct_only; int use_inter_dct_only; + int use_intra_default_tx_only; int quant_b_adapt; + COST_UPDATE_TYPE coeff_cost_upd_freq; + COST_UPDATE_TYPE mode_cost_upd_freq; int border_in_pixels; + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; + // Bit mask to specify which tier each of the 32 possible operating points + // conforms to. + unsigned int tier_mask; } AV1EncoderConfig; static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) { @@ -418,7 +453,7 @@ typedef struct FRAME_COUNTS { unsigned int interintra[BLOCK_SIZE_GROUPS][2]; unsigned int interintra_mode[BLOCK_SIZE_GROUPS][INTERINTRA_MODES]; unsigned int wedge_interintra[BLOCK_SIZES_ALL][2]; - unsigned int compound_type[BLOCK_SIZES_ALL][COMPOUND_TYPES - 1]; + unsigned int compound_type[BLOCK_SIZES_ALL][MASKED_COMPOUND_TYPES]; unsigned int motion_mode[BLOCK_SIZES_ALL][MOTION_MODES]; unsigned int obmc[BLOCK_SIZES_ALL][2]; unsigned int intra_inter[INTRA_INTER_CONTEXTS][2]; @@ -487,6 +522,11 @@ typedef struct inter_modes_info { int64_t sse_arr[MAX_INTER_MODES]; int64_t est_rd_arr[MAX_INTER_MODES]; RdIdxPair rd_idx_pair_arr[MAX_INTER_MODES]; + bool true_rd_arr[MAX_INTER_MODES]; + uint8_t blk_skip_arr[MAX_INTER_MODES][MAX_MIB_SIZE * MAX_MIB_SIZE]; + RD_STATS rd_cost_arr[MAX_INTER_MODES]; + RD_STATS rd_cost_y_arr[MAX_INTER_MODES]; + RD_STATS rd_cost_uv_arr[MAX_INTER_MODES]; } InterModesInfo; // Encoder row synchronization @@ -593,15 +633,84 @@ typedef struct { YV12_BUFFER_CONFIG buf; } EncRefCntBuffer; -#if CONFIG_COLLECT_PARTITION_STATS +#if CONFIG_COLLECT_PARTITION_STATS == 2 typedef struct PartitionStats { int partition_decisions[6][EXT_PARTITION_TYPES]; int partition_attempts[6][EXT_PARTITION_TYPES]; + int64_t partition_times[6][EXT_PARTITION_TYPES]; int partition_redo; } PartitionStats; #endif +#if CONFIG_COLLECT_COMPONENT_TIMING +#include "aom_ports/aom_timer.h" +// Adjust the following to add new components. +enum { + encode_frame_to_data_rate_time, + encode_with_recode_loop_time, + loop_filter_time, + cdef_time, + loop_restoration_time, + av1_pack_bitstream_final_time, + av1_encode_frame_time, + av1_compute_global_motion_time, + av1_setup_motion_field_time, + encode_sb_time, + first_partition_search_pass_time, + rd_pick_partition_time, + rd_pick_sb_modes_time, + av1_rd_pick_intra_mode_sb_time, + av1_rd_pick_inter_mode_sb_time, + handle_intra_mode_time, + handle_inter_mode_time, + do_tx_search_time, + handle_newmv_time, + compound_type_rd_time, + interpolation_filter_search_time, + motion_mode_rd_time, + kTimingComponents, +} UENUM1BYTE(TIMING_COMPONENT); + +static INLINE char const *get_component_name(int index) { + switch (index) { + case encode_frame_to_data_rate_time: + return "encode_frame_to_data_rate_time"; + case encode_with_recode_loop_time: return "encode_with_recode_loop_time"; + case loop_filter_time: return "loop_filter_time"; + case cdef_time: return "cdef_time"; + case loop_restoration_time: return "loop_restoration_time"; + case av1_pack_bitstream_final_time: return "av1_pack_bitstream_final_time"; + case av1_encode_frame_time: return "av1_encode_frame_time"; + case av1_compute_global_motion_time: + return "av1_compute_global_motion_time"; + case av1_setup_motion_field_time: return "av1_setup_motion_field_time"; + case encode_sb_time: return "encode_sb_time"; + case first_partition_search_pass_time: + return "first_partition_search_pass_time"; + case rd_pick_partition_time: return "rd_pick_partition_time"; + case rd_pick_sb_modes_time: return "rd_pick_sb_modes_time"; + case av1_rd_pick_intra_mode_sb_time: + return "av1_rd_pick_intra_mode_sb_time"; + case av1_rd_pick_inter_mode_sb_time: + return "av1_rd_pick_inter_mode_sb_time"; + case handle_intra_mode_time: return "handle_intra_mode_time"; + case handle_inter_mode_time: return "handle_inter_mode_time"; + case do_tx_search_time: return "do_tx_search_time"; + case handle_newmv_time: return "handle_newmv_time"; + case compound_type_rd_time: return "compound_type_rd_time"; + case interpolation_filter_search_time: + return "interpolation_filter_search_time"; + case motion_mode_rd_time: return "motion_mode_rd_time"; + default: assert(0); + } + return "error"; +} +#endif + +// The maximum number of internal ARFs except ALTREF_FRAME +#define MAX_INTERNAL_ARFS (REF_FRAMES - BWDREF_FRAME - 1) + typedef struct AV1_COMP { QUANTS quants; ThreadData td; @@ -615,7 +724,6 @@ typedef struct AV1_COMP { struct lookahead_entry *alt_ref_source; int no_show_kf; - int optimize_speed_feature; int optimize_seg_arr[MAX_SEGMENTS]; YV12_BUFFER_CONFIG *source; @@ -630,6 +738,9 @@ typedef struct AV1_COMP { // For a still frame, this flag is set to 1 to skip partition search. int partition_search_skippable_frame; + // The following item corresponds to two_pass_partition_search speed features. + int two_pass_partition_search; + double csm_rate_array[32]; double m_rate_array[32]; int rate_size; @@ -665,13 +776,6 @@ typedef struct AV1_COMP { // frame of the same type as the current frame). int fb_of_context_type[REF_FRAMES]; - // When true, a new rule for backward (future) reference frames is in effect: - // - BWDREF_FRAME is always the closest future frame available - // - ALTREF2_FRAME is always the 2nd closest future frame available - // - 'refresh_bwd_ref_frame' flag is used for updating both the BWDREF_FRAME - // and ALTREF2_FRAME. ('refresh_alt2_ref_frame' flag is irrelevant). - int new_bwdref_update_rule; - int ext_refresh_frame_flags_pending; int ext_refresh_last_frame; int ext_refresh_golden_frame; @@ -709,12 +813,6 @@ typedef struct AV1_COMP { RATE_CONTROL rc; double framerate; - // Relevant for an inter frame. - // - Index '0' corresponds to the values for the currently coded frame. - // - Indices LAST_FRAME ... EXTREF_FRAMES are used to store values for all the - // possible inter reference frames. - int interp_filter_selected[REF_FRAMES + 1][SWITCHABLE]; - struct aom_codec_pkt_list *output_pkt_list; MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS]; @@ -741,12 +839,10 @@ typedef struct AV1_COMP { fractional_mv_step_fp *find_fractional_mv_step; av1_diamond_search_fn_t diamond_search_sad; aom_variance_fn_ptr_t fn_ptr[BLOCK_SIZES_ALL]; + +#if CONFIG_INTERNAL_STATS uint64_t time_receive_data; uint64_t time_compress_data; - uint64_t time_pick_lpf; - -#if CONFIG_FP_MB_STATS - int use_fp_mb_stats; #endif TWO_PASS twopass; @@ -802,9 +898,11 @@ typedef struct AV1_COMP { int resize_pending_width; int resize_pending_height; - int frame_flags; - - search_site_config ss_cfg; + // ss_cfg[SS_CFG_LOOKAHEAD] : used in following cases + // -> temporal filtering + // -> intrabc + // ss_cfg[SS_CFG_SRC] : used everywhere except above mentioned cases + search_site_config ss_cfg[SS_CFG_TOTAL]; TileDataEnc *tile_data; int allocated_tiles; // Keep track of memory allocated for tiles. @@ -824,17 +922,24 @@ typedef struct AV1_COMP { // VARIANCE_AQ segment map refresh int vaq_refresh; + // VAR_BASED_PARTITION thresholds + // 0 - threshold_128x128; 1 - threshold_64x64; + // 2 - threshold_32x32; 3 - threshold_16x16; + // 4 - vbp_threshold_8x8; + int64_t vbp_thresholds[5]; + int64_t vbp_threshold_minmax; + int64_t vbp_threshold_sad; + int64_t vbp_threshold_copy; + BLOCK_SIZE vbp_bsize_min; + // Multi-threading int num_workers; AVxWorker *workers; struct EncWorkerData *tile_thr_data; int existing_fb_idx_to_show; - int is_arf_filter_off[MAX_EXT_ARFS + 1]; - int num_extra_arfs; - int arf_pos_in_gf[MAX_EXT_ARFS + 1]; - int arf_pos_for_ovrly[MAX_EXT_ARFS + 1]; + int is_arf_filter_off[MAX_INTERNAL_ARFS + 1]; int global_motion_search_done; - int extra_arf_allowed; + int internal_altref_allowed; // A flag to indicate if intrabc is ever used in current frame. int intrabc_used; int dv_cost[2][MV_VALS]; @@ -873,9 +978,25 @@ typedef struct AV1_COMP { #endif // Set if screen content is set or relevant tools are enabled int is_screen_content_type; -#if CONFIG_COLLECT_PARTITION_STATS +#if CONFIG_COLLECT_PARTITION_STATS == 2 PartitionStats partition_stats; #endif + +#if CONFIG_COLLECT_COMPONENT_TIMING + // component_time[] are initialized to zero while encoder starts. + uint64_t component_time[kTimingComponents]; + struct aom_usec_timer component_timer[kTimingComponents]; + // frame_component_time[] are initialized to zero at beginning of each frame. + uint64_t frame_component_time[kTimingComponents]; +#endif + + // The following data are for AV1 bitstream levels. + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; + int keep_level_stats; + AV1LevelInfo level_info[MAX_NUM_OPERATING_POINTS]; + // Count the number of OBU_FRAME and OBU_FRAME_HEADER for level calculation. + int frame_header_count; + FrameWindowBuffer frame_window_buffer; } AV1_COMP; typedef struct { @@ -892,14 +1013,26 @@ struct EncodeFrameParams { int primary_ref_frame; int order_offset; int show_frame; + int refresh_frame_flags; - // This is a bitmask of which reference slots can be used in this frame + int show_existing_frame; + int existing_fb_idx_to_show; + + // Bitmask of which reference buffers may be referenced by this frame int ref_frame_flags; + // Reference buffer assignment for this frame. + int remapped_ref_idx[REF_FRAMES]; + + // Flags which determine which reference buffers are refreshed by this frame + int refresh_last_frame; + int refresh_golden_frame; + int refresh_bwd_ref_frame; + int refresh_alt2_ref_frame; + int refresh_alt_ref_frame; + // Speed level to use for this frame: Bigger number means faster. int speed; - - unsigned int *frame_flags; }; typedef struct EncodeFrameParams EncodeFrameParams; @@ -1112,6 +1245,48 @@ static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) { cm->current_frame.frame_type == KEY_FRAME); } +// Lighter version of set_offsets that only sets the mode info +// pointers. +static INLINE void set_mode_info_offsets(const AV1_COMP *const cpi, + MACROBLOCK *const x, + MACROBLOCKD *const xd, int mi_row, + int mi_col) { + const AV1_COMMON *const cm = &cpi->common; + const int idx_str = xd->mi_stride * mi_row + mi_col; + xd->mi = cm->mi_grid_visible + idx_str; + xd->mi[0] = cm->mi + idx_str; + x->mbmi_ext = cpi->mbmi_ext_base + (mi_row * cm->mi_cols + mi_col); +} + +// Check to see if the given partition size is allowed for a specified number +// of mi block rows and columns remaining in the image. +// If not then return the largest allowed partition size +static INLINE BLOCK_SIZE find_partition_size(BLOCK_SIZE bsize, int rows_left, + int cols_left, int *bh, int *bw) { + int int_size = (int)bsize; + if (rows_left <= 0 || cols_left <= 0) { + return AOMMIN(bsize, BLOCK_8X8); + } else { + for (; int_size > 0; int_size -= 3) { + *bh = mi_size_high[int_size]; + *bw = mi_size_wide[int_size]; + if ((*bh <= rows_left) && (*bw <= cols_left)) { + break; + } + } + } + return (BLOCK_SIZE)int_size; +} + +static const uint8_t av1_ref_frame_flag_list[REF_FRAMES] = { 0, + AOM_LAST_FLAG, + AOM_LAST2_FLAG, + AOM_LAST3_FLAG, + AOM_GOLD_FLAG, + AOM_BWD_FLAG, + AOM_ALT2_FLAG, + AOM_ALT_FLAG }; + // Returns a Sequence Header OBU stored in an aom_fixed_buf_t, or NULL upon // failure. When a non-NULL aom_fixed_buf_t pointer is returned by this // function, the memory must be freed by the caller. Both the buf member of the @@ -1123,7 +1298,7 @@ static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) { // field. aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi); -#if CONFIG_COLLECT_PARTITION_STATS +#if CONFIG_COLLECT_PARTITION_STATS == 2 static INLINE void av1_print_partition_stats(PartitionStats *part_stats) { FILE *f = fopen("partition_stats.csv", "w"); if (!f) { @@ -1137,6 +1312,9 @@ static INLINE void av1_print_partition_stats(PartitionStats *part_stats) { for (int part = 0; part < EXT_PARTITION_TYPES; part++) { fprintf(f, "attempt_%d,", part); } + for (int part = 0; part < EXT_PARTITION_TYPES; part++) { + fprintf(f, "time_%d,", part); + } fprintf(f, "\n"); const int bsizes[6] = { 128, 64, 32, 16, 8, 4 }; @@ -1149,6 +1327,9 @@ static INLINE void av1_print_partition_stats(PartitionStats *part_stats) { for (int part = 0; part < EXT_PARTITION_TYPES; part++) { fprintf(f, "%d,", part_stats->partition_attempts[bsize_idx][part]); } + for (int part = 0; part < EXT_PARTITION_TYPES; part++) { + fprintf(f, "%ld,", part_stats->partition_times[bsize_idx][part]); + } fprintf(f, "\n"); } fclose(f); @@ -1156,7 +1337,8 @@ static INLINE void av1_print_partition_stats(PartitionStats *part_stats) { static INLINE int av1_get_bsize_idx_for_part_stats(BLOCK_SIZE bsize) { assert(bsize == BLOCK_128X128 || bsize == BLOCK_64X64 || - bsize == BLOCK_32X32 || bsize == BLOCK_16X16 || bsize == BLOCK_8X8); + bsize == BLOCK_32X32 || bsize == BLOCK_16X16 || bsize == BLOCK_8X8 || + bsize == BLOCK_4X4); switch (bsize) { case BLOCK_128X128: return 0; case BLOCK_64X64: return 1; @@ -1169,6 +1351,27 @@ static INLINE int av1_get_bsize_idx_for_part_stats(BLOCK_SIZE bsize) { } #endif +#if CONFIG_COLLECT_COMPONENT_TIMING +static INLINE void start_timing(AV1_COMP *cpi, int component) { + aom_usec_timer_start(&cpi->component_timer[component]); +} +static INLINE void end_timing(AV1_COMP *cpi, int component) { + aom_usec_timer_mark(&cpi->component_timer[component]); + cpi->frame_component_time[component] += + aom_usec_timer_elapsed(&cpi->component_timer[component]); +} +static INLINE char const *get_frame_type_enum(int type) { + switch (type) { + case 0: return "KEY_FRAME"; + case 1: return "INTER_FRAME"; + case 2: return "INTRA_ONLY_FRAME"; + case 3: return "S_FRAME"; + default: assert(0); + } + return "error"; +} +#endif + #ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/aom/av1/encoder/encodetxb.c b/third_party/aom/av1/encoder/encodetxb.c index 0f1a2666c4..37f4bb9f79 100644 --- a/third_party/aom/av1/encoder/encodetxb.c +++ b/third_party/aom/av1/encoder/encodetxb.c @@ -76,21 +76,12 @@ void av1_free_txb_buf(AV1_COMP *cpi) { aom_free(cpi->coeff_buffer_base); } void av1_set_coeff_buffer(const AV1_COMP *const cpi, MACROBLOCK *const x, int mi_row, int mi_col) { const AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); int mib_size_log2 = cm->seq_params.mib_size_log2; int stride = (cm->mi_cols >> mib_size_log2) + 1; int offset = (mi_row >> mib_size_log2) * stride + (mi_col >> mib_size_log2); - CB_COEFF_BUFFER *coeff_buf = &cpi->coeff_buffer_base[offset]; - const int txb_offset = x->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN); + x->mbmi_ext->cb_coef_buff = &cpi->coeff_buffer_base[offset]; + x->mbmi_ext->cb_offset = x->cb_offset; assert(x->cb_offset < (1 << num_pels_log2_lookup[cm->seq_params.sb_size])); - for (int plane = 0; plane < num_planes; ++plane) { - x->mbmi_ext->tcoeff[plane] = coeff_buf->tcoeff[plane] + x->cb_offset; - x->mbmi_ext->eobs[plane] = coeff_buf->eobs[plane] + txb_offset; - x->mbmi_ext->txb_skip_ctx[plane] = - coeff_buf->txb_skip_ctx[plane] + txb_offset; - x->mbmi_ext->dc_sign_ctx[plane] = - coeff_buf->dc_sign_ctx[plane] + txb_offset; - } } static void write_golomb(aom_writer *w, int level) { @@ -647,10 +638,18 @@ static void write_coeffs_txb_wrap(const AV1_COMMON *cm, MACROBLOCK *x, aom_writer *w, int plane, int block, int blk_row, int blk_col, TX_SIZE tx_size) { MACROBLOCKD *xd = &x->e_mbd; - tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block); - uint16_t eob = x->mbmi_ext->eobs[plane][block]; - TXB_CTX txb_ctx = { x->mbmi_ext->txb_skip_ctx[plane][block], - x->mbmi_ext->dc_sign_ctx[plane][block] }; + const int txb_offset = + x->mbmi_ext->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN); + tran_low_t *tcoeff_txb = + x->mbmi_ext->cb_coef_buff->tcoeff[plane] + x->mbmi_ext->cb_offset; + uint16_t *eob_txb = x->mbmi_ext->cb_coef_buff->eobs[plane] + txb_offset; + uint8_t *txb_skip_ctx_txb = + x->mbmi_ext->cb_coef_buff->txb_skip_ctx[plane] + txb_offset; + int *dc_sign_ctx_txb = + x->mbmi_ext->cb_coef_buff->dc_sign_ctx[plane] + txb_offset; + tran_low_t *tcoeff = BLOCK_OFFSET(tcoeff_txb, block); + uint16_t eob = eob_txb[block]; + TXB_CTX txb_ctx = { txb_skip_ctx_txb[block], dc_sign_ctx_txb[block] }; av1_write_coeffs_txb(cm, xd, w, blk_row, blk_col, plane, tx_size, tcoeff, eob, &txb_ctx); } @@ -1489,6 +1488,36 @@ static AOM_FORCE_INLINE void update_coeff_simple( } } +static INLINE void update_coeff_eob_fast(int *eob, int shift, + const int16_t *dequant_ptr, + const int16_t *scan, + const tran_low_t *coeff_ptr, + tran_low_t *qcoeff_ptr, + tran_low_t *dqcoeff_ptr) { + // TODO(sarahparker) make this work for aomqm + int eob_out = *eob; + int zbin[2] = { dequant_ptr[0] + ROUND_POWER_OF_TWO(dequant_ptr[0] * 70, 7), + dequant_ptr[1] + ROUND_POWER_OF_TWO(dequant_ptr[1] * 70, 7) }; + + for (int i = *eob - 1; i >= 0; i--) { + const int rc = scan[i]; + const int qcoeff = qcoeff_ptr[rc]; + const int coeff = coeff_ptr[rc]; + const int coeff_sign = (coeff >> 31); + int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + + if (((abs_coeff << (1 + shift)) < zbin[rc != 0]) || (qcoeff == 0)) { + eob_out--; + qcoeff_ptr[rc] = 0; + dqcoeff_ptr[rc] = 0; + } else { + break; + } + } + + *eob = eob_out; +} + static AOM_FORCE_INLINE void update_coeff_eob( int *accu_rate, int64_t *accu_dist, int *eob, int *nz_num, int *nz_ci, int si, TX_SIZE tx_size, TX_CLASS tx_class, int bwl, int height, @@ -1624,35 +1653,44 @@ static INLINE void update_skip(int *accu_rate, int64_t accu_dist, int *eob, int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, int block, TX_SIZE tx_size, TX_TYPE tx_type, const TXB_CTX *const txb_ctx, int *rate_cost, - int sharpness) { - const AV1_COMMON *cm = &cpi->common; + int sharpness, int fast_mode) { MACROBLOCKD *xd = &x->e_mbd; + struct macroblockd_plane *pd = &xd->plane[plane]; + const struct macroblock_plane *p = &x->plane[plane]; + const SCAN_ORDER *scan_order = get_scan(tx_size, tx_type); + const int16_t *scan = scan_order->scan; + const int shift = av1_get_tx_scale(tx_size); + int eob = p->eobs[block]; + const int16_t *dequant = p->dequant_QTX; + tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block); + tran_low_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block); + const tran_low_t *tcoeff = BLOCK_OFFSET(p->coeff, block); + + if (fast_mode) { + update_coeff_eob_fast(&eob, shift, dequant, scan, tcoeff, qcoeff, dqcoeff); + p->eobs[block] = eob; + if (eob == 0) { + *rate_cost = av1_cost_skip_txb(x, txb_ctx, plane, tx_size); + return eob; + } + } + + const AV1_COMMON *cm = &cpi->common; const PLANE_TYPE plane_type = get_plane_type(plane); const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); const TX_CLASS tx_class = tx_type_to_class[tx_type]; const MB_MODE_INFO *mbmi = xd->mi[0]; - const struct macroblock_plane *p = &x->plane[plane]; - struct macroblockd_plane *pd = &xd->plane[plane]; - tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block); - tran_low_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block); - const tran_low_t *tcoeff = BLOCK_OFFSET(p->coeff, block); - const int16_t *dequant = p->dequant_QTX; const int bwl = get_txb_bwl(tx_size); const int width = get_txb_wide(tx_size); const int height = get_txb_high(tx_size); assert(width == (1 << bwl)); const int is_inter = is_inter_block(mbmi); - const SCAN_ORDER *scan_order = get_scan(tx_size, tx_type); - const int16_t *scan = scan_order->scan; const LV_MAP_COEFF_COST *txb_costs = &x->coeff_costs[txs_ctx][plane_type]; const int eob_multi_size = txsize_log2_minus4[tx_size]; const LV_MAP_EOB_COST *txb_eob_costs = &x->eob_costs[eob_multi_size][plane_type]; - const int shift = av1_get_tx_scale(tx_size); - const int64_t rdmult = - ((x->rdmult * plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8))) + - 2) >> + const int rshift = (sharpness + (cpi->oxcf.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4 ? 7 - mbmi->segment_id @@ -1661,10 +1699,14 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, cpi->oxcf.deltaq_mode > NO_DELTA_Q && x->sb_energy_level < 0 ? (3 - x->sb_energy_level) : 0)); + const int64_t rdmult = + (((int64_t)x->rdmult * + (plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8)))) + + 2) >> + rshift; uint8_t levels_buf[TX_PAD_2D]; uint8_t *const levels = set_levels(levels_buf, width); - int eob = p->eobs[block]; if (eob > 1) av1_txb_init_levels(qcoeff, width, height, levels); @@ -1705,7 +1747,7 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, #define UPDATE_COEFF_EOB_CASE(tx_class_literal) \ case tx_class_literal: \ - for (; si >= 0 && nz_num <= max_nz_num; --si) { \ + for (; si >= 0 && nz_num <= max_nz_num && !fast_mode; --si) { \ update_coeff_eob(&accu_rate, &accu_dist, &eob, &nz_num, nz_ci, si, \ tx_size, tx_class_literal, bwl, height, \ txb_ctx->dc_sign_ctx, rdmult, shift, dequant, scan, \ @@ -1798,7 +1840,8 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, const int shift = av1_get_tx_scale(tx_size); const int64_t rdmult = - ((x->rdmult * plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8))) + + (((int64_t)x->rdmult * plane_rd_mult[is_inter][plane_type] + << (2 * (xd->bd - 8))) + 2) >> 2; uint8_t levels_buf[TX_PAD_2D]; @@ -1965,15 +2008,22 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row, 2); } - x->mbmi_ext->txb_skip_ctx[plane][block] = txb_ctx.txb_skip_ctx; - x->mbmi_ext->eobs[plane][block] = eob; + const int txb_offset = + x->mbmi_ext->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN); + uint16_t *eob_txb = x->mbmi_ext->cb_coef_buff->eobs[plane] + txb_offset; + uint8_t *txb_skip_ctx_txb = + x->mbmi_ext->cb_coef_buff->txb_skip_ctx[plane] + txb_offset; + txb_skip_ctx_txb[block] = txb_ctx.txb_skip_ctx; + eob_txb[block] = eob; if (eob == 0) { av1_set_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col, blk_row); return; } - tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block); + tran_low_t *tcoeff_txb = + x->mbmi_ext->cb_coef_buff->tcoeff[plane] + x->mbmi_ext->cb_offset; + tran_low_t *tcoeff = BLOCK_OFFSET(tcoeff_txb, block); const int segment_id = mbmi->segment_id; const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size); const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block); @@ -2066,7 +2116,9 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row, #endif // CONFIG_ENTROPY_STATS if (allow_update_cdf) update_cdf(ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], dc_sign, 2); - x->mbmi_ext->dc_sign_ctx[plane][block] = dc_sign_ctx; + int *dc_sign_ctx_txb = + x->mbmi_ext->cb_coef_buff->dc_sign_ctx[plane] + txb_offset; + dc_sign_ctx_txb[block] = dc_sign_ctx; } const int cul_level = av1_get_txb_entropy_context(tcoeff, scan_order, eob); diff --git a/third_party/aom/av1/encoder/encodetxb.h b/third_party/aom/av1/encoder/encodetxb.h index bfc49dea8c..06825908d0 100644 --- a/third_party/aom/av1/encoder/encodetxb.h +++ b/third_party/aom/av1/encoder/encodetxb.h @@ -78,7 +78,7 @@ void hbt_destroy(); int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, int block, TX_SIZE tx_size, TX_TYPE tx_type, const TXB_CTX *const txb_ctx, int *rate_cost, - int sharpness); + int sharpness, int fast_mode); // These numbers are empirically obtained. static const int plane_rd_mult[REF_TYPES][PLANE_TYPES] = { diff --git a/third_party/aom/av1/encoder/ethread.c b/third_party/aom/av1/encoder/ethread.c index 77fb811b14..c8c2107f0b 100644 --- a/third_party/aom/av1/encoder/ethread.c +++ b/third_party/aom/av1/encoder/ethread.c @@ -236,26 +236,34 @@ static void switch_tile_and_get_next_job(AV1_COMP *const cpi, int *cur_tile_id, int tile_index = tile_row * tile_cols + tile_col; TileDataEnc *this_tile = &cpi->tile_data[tile_index]; AV1RowMTInfo *row_mt_info = &this_tile->row_mt_info; - int num_mis_to_encode = - this_tile->tile_info.mi_row_end - row_mt_info->current_mi_row; + int num_sb_rows_in_tile = + av1_get_sb_rows_in_tile(cm, this_tile->tile_info); + int num_sb_cols_in_tile = + av1_get_sb_cols_in_tile(cm, this_tile->tile_info); + int theoretical_limit_on_threads = + AOMMIN((num_sb_cols_in_tile + 1) >> 1, num_sb_rows_in_tile); + int num_threads_working = row_mt_info->num_threads_working; + if (num_threads_working < theoretical_limit_on_threads) { + int num_mis_to_encode = + this_tile->tile_info.mi_row_end - row_mt_info->current_mi_row; - // Tile to be processed by this thread is selected on the basis of - // availability of jobs: - // 1) If jobs are available, tile to be processed is chosen on the - // basis of minimum number of threads working for that tile. If two or - // more tiles have same number of threads working for them, then the tile - // with maximum number of jobs available will be chosen. - // 2) If no jobs are available, then end_of_frame is reached. - if (num_mis_to_encode > 0) { - int num_threads_working = row_mt_info->num_threads_working; - if (num_threads_working < min_num_threads_working) { - min_num_threads_working = num_threads_working; - max_mis_to_encode = 0; - } - if (num_threads_working == min_num_threads_working && - num_mis_to_encode > max_mis_to_encode) { - tile_id = tile_index; - max_mis_to_encode = num_mis_to_encode; + // Tile to be processed by this thread is selected on the basis of + // availability of jobs: + // 1) If jobs are available, tile to be processed is chosen on the + // basis of minimum number of threads working for that tile. If two or + // more tiles have same number of threads working for them, then the + // tile with maximum number of jobs available will be chosen. + // 2) If no jobs are available, then end_of_frame is reached. + if (num_mis_to_encode > 0) { + if (num_threads_working < min_num_threads_working) { + min_num_threads_working = num_threads_working; + max_mis_to_encode = 0; + } + if (num_threads_working == min_num_threads_working && + num_mis_to_encode > max_mis_to_encode) { + tile_id = tile_index; + max_mis_to_encode = num_mis_to_encode; + } } } } @@ -616,7 +624,7 @@ void av1_encode_tiles_row_mt(AV1_COMP *cpi) { const int tile_rows = cm->tile_rows; MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt; int num_workers = 0; - int total_num_sb_rows = 0; + int total_num_threads_row_mt = 0; int max_sb_rows = 0; if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows) { @@ -631,11 +639,19 @@ void av1_encode_tiles_row_mt(AV1_COMP *cpi) { TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col]; int num_sb_rows_in_tile = av1_get_sb_rows_in_tile(cm, tile_data->tile_info); - total_num_sb_rows += num_sb_rows_in_tile; + int num_sb_cols_in_tile = + av1_get_sb_cols_in_tile(cm, tile_data->tile_info); + total_num_threads_row_mt += + AOMMIN((num_sb_cols_in_tile + 1) >> 1, num_sb_rows_in_tile); max_sb_rows = AOMMAX(max_sb_rows, num_sb_rows_in_tile); } } - num_workers = AOMMIN(cpi->oxcf.max_threads, total_num_sb_rows); + // TODO(ravi.chaudhary@ittiam.com): Currently the percentage of + // post-processing stages in encoder is quiet low, so limiting the number of + // threads to the theoretical limit in row-mt does not have much impact on + // post-processing multi-threading stage. Need to revisit this when + // post-processing time starts shooting up. + num_workers = AOMMIN(cpi->oxcf.max_threads, total_num_threads_row_mt); if (multi_thread_ctxt->allocated_tile_cols != tile_cols || multi_thread_ctxt->allocated_tile_rows != tile_rows || diff --git a/third_party/aom/av1/encoder/firstpass.c b/third_party/aom/av1/encoder/firstpass.c index 8b9513b645..f6a0fb2c17 100644 --- a/third_party/aom/av1/encoder/firstpass.c +++ b/third_party/aom/av1/encoder/firstpass.c @@ -44,63 +44,14 @@ #include "av1/encoder/reconinter_enc.h" #define OUTPUT_FPF 0 -#define ARF_STATS_OUTPUT 0 -#define GROUP_ADAPTIVE_MAXQ 1 - -#define BOOST_BREAKOUT 12.5 -#define BOOST_FACTOR 12.5 -#define FACTOR_PT_LOW 0.70 -#define FACTOR_PT_HIGH 0.90 #define FIRST_PASS_Q 10.0 -#define GF_MAX_BOOST 90.0 #define INTRA_MODE_PENALTY 1024 -#define KF_MIN_FRAME_BOOST 80.0 -#define KF_MAX_FRAME_BOOST 128.0 -#define MIN_ARF_GF_BOOST 240 -#define MIN_DECAY_FACTOR 0.01 -#define MIN_KF_BOOST 300 // Minimum boost for non-static KF interval -#define MIN_STATIC_KF_BOOST 5400 // Minimum boost for static KF interval #define NEW_MV_MODE_PENALTY 32 #define DARK_THRESH 64 -#define DEFAULT_GRP_WEIGHT 1.0 -#define RC_FACTOR_MIN 0.75 -#define RC_FACTOR_MAX 1.75 -#define MIN_FWD_KF_INTERVAL 8 #define NCOUNT_INTRA_THRESH 8192 #define NCOUNT_INTRA_FACTOR 3 -#define NCOUNT_FRAME_II_THRESH 5.0 - -#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x)-0.000001 : (x) + 0.000001) - -#if ARF_STATS_OUTPUT -unsigned int arf_count = 0; -#endif - -// Resets the first pass file to the given position using a relative seek from -// the current position. -static void reset_fpf_position(TWO_PASS *p, const FIRSTPASS_STATS *position) { - p->stats_in = position; -} - -// Read frame stats at an offset from the current position. -static const FIRSTPASS_STATS *read_frame_stats(const TWO_PASS *p, int offset) { - if ((offset >= 0 && p->stats_in + offset >= p->stats_in_end) || - (offset < 0 && p->stats_in + offset < p->stats_in_start)) { - return NULL; - } - - return &p->stats_in[offset]; -} - -static int input_stats(TWO_PASS *p, FIRSTPASS_STATS *fps) { - if (p->stats_in >= p->stats_in_end) return EOF; - - *fps = *p->stats_in; - ++p->stats_in; - return 1; -} static void output_stats(FIRSTPASS_STATS *stats, struct aom_codec_pkt_list *pktlist) { @@ -132,18 +83,7 @@ static void output_stats(FIRSTPASS_STATS *stats, #endif } -#if CONFIG_FP_MB_STATS -static void output_fpmb_stats(uint8_t *this_frame_mb_stats, int stats_size, - struct aom_codec_pkt_list *pktlist) { - struct aom_codec_cx_pkt pkt; - pkt.kind = AOM_CODEC_FPMB_STATS_PKT; - pkt.data.firstpass_mb_stats.buf = this_frame_mb_stats; - pkt.data.firstpass_mb_stats.sz = stats_size * sizeof(*this_frame_mb_stats); - aom_codec_pkt_list_add(pktlist, &pkt); -} -#endif - -static void zero_stats(FIRSTPASS_STATS *section) { +void av1_twopass_zero_stats(FIRSTPASS_STATS *section) { section->frame = 0.0; section->weight = 0.0; section->intra_error = 0.0; @@ -196,98 +136,8 @@ static void accumulate_stats(FIRSTPASS_STATS *section, section->duration += frame->duration; } -static void subtract_stats(FIRSTPASS_STATS *section, - const FIRSTPASS_STATS *frame) { - section->frame -= frame->frame; - section->weight -= frame->weight; - section->intra_error -= frame->intra_error; - section->frame_avg_wavelet_energy -= frame->frame_avg_wavelet_energy; - section->coded_error -= frame->coded_error; - section->sr_coded_error -= frame->sr_coded_error; - section->pcnt_inter -= frame->pcnt_inter; - section->pcnt_motion -= frame->pcnt_motion; - section->pcnt_second_ref -= frame->pcnt_second_ref; - section->pcnt_neutral -= frame->pcnt_neutral; - section->intra_skip_pct -= frame->intra_skip_pct; - section->inactive_zone_rows -= frame->inactive_zone_rows; - section->inactive_zone_cols -= frame->inactive_zone_cols; - section->MVr -= frame->MVr; - section->mvr_abs -= frame->mvr_abs; - section->MVc -= frame->MVc; - section->mvc_abs -= frame->mvc_abs; - section->MVrv -= frame->MVrv; - section->MVcv -= frame->MVcv; - section->mv_in_out_count -= frame->mv_in_out_count; - section->new_mv_count -= frame->new_mv_count; - section->count -= frame->count; - section->duration -= frame->duration; -} - -// Calculate the linear size relative to a baseline of 1080P -#define BASE_SIZE 2073600.0 // 1920x1080 -static double get_linear_size_factor(const AV1_COMP *cpi) { - const double this_area = cpi->initial_width * cpi->initial_height; - return pow(this_area / BASE_SIZE, 0.5); -} - -// Calculate an active area of the image that discounts formatting -// bars and partially discounts other 0 energy areas. -#define MIN_ACTIVE_AREA 0.5 -#define MAX_ACTIVE_AREA 1.0 -static double calculate_active_area(const AV1_COMP *cpi, - const FIRSTPASS_STATS *this_frame) { - double active_pct; - - active_pct = - 1.0 - - ((this_frame->intra_skip_pct / 2) + - ((this_frame->inactive_zone_rows * 2) / (double)cpi->common.mb_rows)); - return fclamp(active_pct, MIN_ACTIVE_AREA, MAX_ACTIVE_AREA); -} - -// Calculate a modified Error used in distributing bits between easier and -// harder frames. -#define ACT_AREA_CORRECTION 0.5 -static double calculate_modified_err(const AV1_COMP *cpi, - const TWO_PASS *twopass, - const AV1EncoderConfig *oxcf, - const FIRSTPASS_STATS *this_frame) { - const FIRSTPASS_STATS *const stats = &twopass->total_stats; - const double av_weight = stats->weight / stats->count; - const double av_err = (stats->coded_error * av_weight) / stats->count; - double modified_error = - av_err * pow(this_frame->coded_error * this_frame->weight / - DOUBLE_DIVIDE_CHECK(av_err), - oxcf->two_pass_vbrbias / 100.0); - - // Correction for active area. Frames with a reduced active area - // (eg due to formatting bars) have a higher error per mb for the - // remaining active MBs. The correction here assumes that coding - // 0.5N blocks of complexity 2X is a little easier than coding N - // blocks of complexity X. - modified_error *= - pow(calculate_active_area(cpi, this_frame), ACT_AREA_CORRECTION); - - return fclamp(modified_error, twopass->modified_error_min, - twopass->modified_error_max); -} - -// This function returns the maximum target rate per frame. -static int frame_max_bits(const RATE_CONTROL *rc, - const AV1EncoderConfig *oxcf) { - int64_t max_bits = ((int64_t)rc->avg_frame_bandwidth * - (int64_t)oxcf->two_pass_vbrmax_section) / - 100; - if (max_bits < 0) - max_bits = 0; - else if (max_bits > rc->max_frame_bandwidth) - max_bits = rc->max_frame_bandwidth; - - return (int)max_bits; -} - void av1_init_first_pass(AV1_COMP *cpi) { - zero_stats(&cpi->twopass.total_stats); + av1_twopass_zero_stats(&cpi->twopass.total_stats); } void av1_end_first_pass(AV1_COMP *cpi) { @@ -386,8 +236,8 @@ static void first_pass_motion_search(AV1_COMP *cpi, MACROBLOCK *x, } // Center the initial step/diamond search on best mv. - tmp_err = cpi->diamond_search_sad(x, &cpi->ss_cfg, &ref_mv_full, &tmp_mv, - step_param, x->sadperbit16, &num00, + tmp_err = cpi->diamond_search_sad(x, &cpi->ss_cfg[SS_CFG_SRC], &ref_mv_full, + &tmp_mv, step_param, x->sadperbit16, &num00, &v_fn_ptr, ref_mv); if (tmp_err < INT_MAX) tmp_err = av1_get_mvpred_var(x, &tmp_mv, ref_mv, &v_fn_ptr, 1); @@ -408,9 +258,9 @@ static void first_pass_motion_search(AV1_COMP *cpi, MACROBLOCK *x, if (num00) { --num00; } else { - tmp_err = cpi->diamond_search_sad(x, &cpi->ss_cfg, &ref_mv_full, &tmp_mv, - step_param + n, x->sadperbit16, &num00, - &v_fn_ptr, ref_mv); + tmp_err = cpi->diamond_search_sad( + x, &cpi->ss_cfg[SS_CFG_SRC], &ref_mv_full, &tmp_mv, step_param + n, + x->sadperbit16, &num00, &v_fn_ptr, ref_mv); if (tmp_err < INT_MAX) tmp_err = av1_get_mvpred_var(x, &tmp_mv, ref_mv, &v_fn_ptr, 1); if (tmp_err < INT_MAX - new_mv_mode_penalty) @@ -440,14 +290,7 @@ static BLOCK_SIZE get_bsize(const AV1_COMMON *cm, int mb_row, int mb_col) { } static int find_fp_qindex(aom_bit_depth_t bit_depth) { - int i; - - for (i = 0; i < QINDEX_RANGE; ++i) - if (av1_convert_qindex_to_q(i, bit_depth) >= FIRST_PASS_Q) break; - - if (i == QINDEX_RANGE) i--; - - return i; + return av1_find_qindex(FIRST_PASS_Q, bit_depth, 0, QINDEX_RANGE - 1); } static double raw_motion_error_stdev(int *raw_motion_err_list, @@ -490,7 +333,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { &cpi->td.pc_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2]->none; int i; - int recon_yoffset, recon_uvoffset; + int recon_yoffset, src_yoffset, recon_uvoffset; int64_t intra_error = 0; int64_t frame_avg_wavelet_energy = 0; int64_t coded_error = 0; @@ -510,7 +353,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { int sum_in_vectors = 0; MV lastmv = kZeroMv; TWO_PASS *twopass = &cpi->twopass; - int recon_y_stride, recon_uv_stride, uv_mb_height; + int recon_y_stride, src_y_stride, recon_uv_stride, uv_mb_height; const YV12_BUFFER_CONFIG *const lst_yv12 = get_ref_frame_yv12_buf(cm, LAST_FRAME); @@ -531,12 +374,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { assert(new_yv12 != NULL); assert(frame_is_intra_only(cm) || (lst_yv12 != NULL)); -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - av1_zero_array(cpi->twopass.frame_mb_stats_buf, cpi->initial_mbs); - } -#endif - + av1_setup_frame_size(cpi); aom_clear_system_state(); xd->mi = cm->mi_grid_visible; @@ -584,7 +422,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { // Tiling is ignored in the first pass. av1_tile_init(&tile, cm, 0, 0); - + src_y_stride = cpi->source->y_stride; recon_y_stride = new_yv12->y_stride; recon_uv_stride = new_yv12->uv_stride; uv_mb_height = 16 >> (new_yv12->y_height > new_yv12->uv_height); @@ -595,6 +433,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { // Reset above block coeffs. xd->up_available = (mb_row != 0); recon_yoffset = (mb_row * recon_y_stride * 16); + src_yoffset = (mb_row * src_y_stride * 16); recon_uvoffset = (mb_row * recon_uv_stride * uv_mb_height); // Set up limit values for motion vectors to prevent them extending @@ -610,10 +449,6 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { double log_intra; int level_sample; -#if CONFIG_FP_MB_STATS - const int mb_index = mb_row * cm->mb_cols + mb_col; -#endif - aom_clear_system_state(); const int idx_str = xd->mi_stride * mb_row * mb_scale + mb_col * mb_scale; @@ -640,11 +475,6 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { av1_encode_intra_block_plane(cpi, x, bsize, 0, 0, mb_row * 2, mb_col * 2); this_error = aom_get_mb_ss(x->plane[0].src_diff); - // Keep a record of blocks that have almost no intra error residual - // (i.e. are in effect completely flat and untextured in the intra - // domain). In natural videos this is uncommon, but it is much more - // common in animations, graphics and screen content, so may be used - // as a signal to detect these types of content. if (this_error < UL_INTRA_THRESH) { ++intra_skip_count; } else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) { @@ -702,13 +532,6 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { } } -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - // initialization - cpi->twopass.frame_mb_stats_buf[mb_index] = 0; - } -#endif - // Set up limit values for motion vectors to prevent them extending // outside the UMV borders. x->mv_limits.col_min = -((mb_col * 16) + BORDER_MV_PIXELS_B16); @@ -734,7 +557,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { // frame as the reference. Skip the further motion search on // reconstructed frame if this error is small. unscaled_last_source_buf_2d.buf = - cpi->unscaled_last_source->y_buffer + recon_yoffset; + cpi->unscaled_last_source->y_buffer + src_yoffset; unscaled_last_source_buf_2d.stride = cpi->unscaled_last_source->y_stride; if (is_cur_buf_hbd(xd)) { @@ -807,20 +630,6 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { best_ref_mv.row = 0; best_ref_mv.col = 0; -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - // intra predication statistics - cpi->twopass.frame_mb_stats_buf[mb_index] = 0; - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_DCINTRA_MASK; - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_MOTION_ZERO_MASK; - if (this_error > FPMB_ERROR_LARGE_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LARGE_MASK; - } else if (this_error < FPMB_ERROR_SMALL_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_SMALL_MASK; - } - } -#endif - if (motion_error <= this_error) { aom_clear_system_state(); @@ -860,50 +669,9 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { best_ref_mv = mv; -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - // inter predication statistics - cpi->twopass.frame_mb_stats_buf[mb_index] = 0; - cpi->twopass.frame_mb_stats_buf[mb_index] &= ~FPMB_DCINTRA_MASK; - cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_MOTION_ZERO_MASK; - if (this_error > FPMB_ERROR_LARGE_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_LARGE_MASK; - } else if (this_error < FPMB_ERROR_SMALL_TH) { - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_ERROR_SMALL_MASK; - } - } -#endif - if (!is_zero_mv(&mv)) { ++mvcount; -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - cpi->twopass.frame_mb_stats_buf[mb_index] &= - ~FPMB_MOTION_ZERO_MASK; - // check estimated motion direction - if (mv.col > 0 && mv.col >= abs(mv.row)) { - // right direction - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_MOTION_RIGHT_MASK; - } else if (mv.row < 0 && abs(mv.row) >= abs(mv.col)) { - // up direction - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_MOTION_UP_MASK; - } else if (mv.col < 0 && abs(mv.col) >= abs(mv.row)) { - // left direction - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_MOTION_LEFT_MASK; - } else { - // down direction - cpi->twopass.frame_mb_stats_buf[mb_index] |= - FPMB_MOTION_DOWN_MASK; - } - } -#endif - // Non-zero vector, was it different from the last non zero vector? if (!is_equal_mv(&mv, &lastmv)) ++new_mv_count; lastmv = mv; @@ -947,6 +715,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { x->plane[2].src.buf += uv_mb_height; recon_yoffset += 16; + src_yoffset += 16; recon_uvoffset += uv_mb_height; } // Adjust to the next row of MBs. @@ -1037,13 +806,6 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { twopass->this_frame_stats = fps; output_stats(&twopass->this_frame_stats, cpi->output_pkt_list); accumulate_stats(&twopass->total_stats, &fps); - -#if CONFIG_FP_MB_STATS - if (cpi->use_fp_mb_stats) { - output_fpmb_stats(twopass->frame_mb_stats_buf, cpi->initial_mbs, - cpi->output_pkt_list); - } -#endif } // Copy the previous Last Frame back into gf and and arf buffers if @@ -1096,2099 +858,3 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { ++current_frame->frame_number; } - -static double calc_correction_factor(double err_per_mb, double err_divisor, - double pt_low, double pt_high, int q, - aom_bit_depth_t bit_depth) { - const double error_term = err_per_mb / err_divisor; - - // Adjustment based on actual quantizer to power term. - const double power_term = - AOMMIN(av1_convert_qindex_to_q(q, bit_depth) * 0.01 + pt_low, pt_high); - - // Calculate correction factor. - if (power_term < 1.0) assert(error_term >= 0.0); - - return fclamp(pow(error_term, power_term), 0.05, 5.0); -} - -#define ERR_DIVISOR 100.0 -static int get_twopass_worst_quality(const AV1_COMP *cpi, - const double section_err, - double inactive_zone, - int section_target_bandwidth, - double group_weight_factor) { - const RATE_CONTROL *const rc = &cpi->rc; - const AV1EncoderConfig *const oxcf = &cpi->oxcf; - - inactive_zone = fclamp(inactive_zone, 0.0, 1.0); - - if (section_target_bandwidth <= 0) { - return rc->worst_quality; // Highest value allowed - } else { - const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) - ? cpi->initial_mbs - : cpi->common.MBs; - const int active_mbs = AOMMAX(1, num_mbs - (int)(num_mbs * inactive_zone)); - const double av_err_per_mb = section_err / active_mbs; - const double speed_term = 1.0; - double ediv_size_correction; - const int target_norm_bits_per_mb = - (int)((uint64_t)section_target_bandwidth << BPER_MB_NORMBITS) / - active_mbs; - int q; - - // Larger image formats are expected to be a little harder to code - // relatively given the same prediction error score. This in part at - // least relates to the increased size and hence coding overheads of - // motion vectors. Some account of this is made through adjustment of - // the error divisor. - ediv_size_correction = - AOMMAX(0.2, AOMMIN(5.0, get_linear_size_factor(cpi))); - if (ediv_size_correction < 1.0) - ediv_size_correction = -(1.0 / ediv_size_correction); - ediv_size_correction *= 4.0; - - // Try and pick a max Q that will be high enough to encode the - // content at the given rate. - for (q = rc->best_quality; q < rc->worst_quality; ++q) { - const double factor = calc_correction_factor( - av_err_per_mb, ERR_DIVISOR - ediv_size_correction, FACTOR_PT_LOW, - FACTOR_PT_HIGH, q, cpi->common.seq_params.bit_depth); - const int bits_per_mb = av1_rc_bits_per_mb( - INTER_FRAME, q, factor * speed_term * group_weight_factor, - cpi->common.seq_params.bit_depth); - if (bits_per_mb <= target_norm_bits_per_mb) break; - } - - // Restriction on active max q for constrained quality mode. - if (cpi->oxcf.rc_mode == AOM_CQ) q = AOMMAX(q, oxcf->cq_level); - return q; - } -} - -static void setup_rf_level_maxq(AV1_COMP *cpi) { - int i; - RATE_CONTROL *const rc = &cpi->rc; - for (i = INTER_NORMAL; i < RATE_FACTOR_LEVELS; ++i) { - int qdelta = av1_frame_type_qdelta(cpi, i, rc->worst_quality); - rc->rf_level_maxq[i] = AOMMAX(rc->worst_quality + qdelta, rc->best_quality); - } -} - -void av1_init_second_pass(AV1_COMP *cpi) { - const AV1EncoderConfig *const oxcf = &cpi->oxcf; - TWO_PASS *const twopass = &cpi->twopass; - double frame_rate; - FIRSTPASS_STATS *stats; - - zero_stats(&twopass->total_stats); - zero_stats(&twopass->total_left_stats); - - if (!twopass->stats_in_end) return; - - stats = &twopass->total_stats; - - *stats = *twopass->stats_in_end; - twopass->total_left_stats = *stats; - - frame_rate = 10000000.0 * stats->count / stats->duration; - // Each frame can have a different duration, as the frame rate in the source - // isn't guaranteed to be constant. The frame rate prior to the first frame - // encoded in the second pass is a guess. However, the sum duration is not. - // It is calculated based on the actual durations of all frames from the - // first pass. - av1_new_framerate(cpi, frame_rate); - twopass->bits_left = - (int64_t)(stats->duration * oxcf->target_bandwidth / 10000000.0); - - // This variable monitors how far behind the second ref update is lagging. - twopass->sr_update_lag = 1; - - // Scan the first pass file and calculate a modified total error based upon - // the bias/power function used to allocate bits. - { - const double avg_error = - stats->coded_error / DOUBLE_DIVIDE_CHECK(stats->count); - const FIRSTPASS_STATS *s = twopass->stats_in; - double modified_error_total = 0.0; - twopass->modified_error_min = - (avg_error * oxcf->two_pass_vbrmin_section) / 100; - twopass->modified_error_max = - (avg_error * oxcf->two_pass_vbrmax_section) / 100; - while (s < twopass->stats_in_end) { - modified_error_total += calculate_modified_err(cpi, twopass, oxcf, s); - ++s; - } - twopass->modified_error_left = modified_error_total; - } - - // Reset the vbr bits off target counters - cpi->rc.vbr_bits_off_target = 0; - cpi->rc.vbr_bits_off_target_fast = 0; - - cpi->rc.rate_error_estimate = 0; - - // Static sequence monitor variables. - twopass->kf_zeromotion_pct = 100; - twopass->last_kfgroup_zeromotion_pct = 100; - - if (oxcf->resize_mode != RESIZE_NONE) { - setup_rf_level_maxq(cpi); - } -} - -#define SR_DIFF_PART 0.0015 -#define MOTION_AMP_PART 0.003 -#define INTRA_PART 0.005 -#define DEFAULT_DECAY_LIMIT 0.75 -#define LOW_SR_DIFF_TRHESH 0.1 -#define SR_DIFF_MAX 128.0 - -static double get_sr_decay_rate(const AV1_COMP *cpi, - const FIRSTPASS_STATS *frame) { - const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs - : cpi->common.MBs; - double sr_diff = (frame->sr_coded_error - frame->coded_error) / num_mbs; - double sr_decay = 1.0; - double modified_pct_inter; - double modified_pcnt_intra; - const double motion_amplitude_factor = - frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) / 2); - - modified_pct_inter = frame->pcnt_inter; - if ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) < - (double)NCOUNT_FRAME_II_THRESH) { - modified_pct_inter = frame->pcnt_inter - frame->pcnt_neutral; - } - modified_pcnt_intra = 100 * (1.0 - modified_pct_inter); - - if ((sr_diff > LOW_SR_DIFF_TRHESH)) { - sr_diff = AOMMIN(sr_diff, SR_DIFF_MAX); - sr_decay = 1.0 - (SR_DIFF_PART * sr_diff) - - (MOTION_AMP_PART * motion_amplitude_factor) - - (INTRA_PART * modified_pcnt_intra); - } - return AOMMAX(sr_decay, AOMMIN(DEFAULT_DECAY_LIMIT, modified_pct_inter)); -} - -// This function gives an estimate of how badly we believe the prediction -// quality is decaying from frame to frame. -static double get_zero_motion_factor(const AV1_COMP *cpi, - const FIRSTPASS_STATS *frame) { - const double zero_motion_pct = frame->pcnt_inter - frame->pcnt_motion; - double sr_decay = get_sr_decay_rate(cpi, frame); - return AOMMIN(sr_decay, zero_motion_pct); -} - -#define ZM_POWER_FACTOR 0.75 - -static double get_prediction_decay_rate(const AV1_COMP *cpi, - const FIRSTPASS_STATS *next_frame) { - const double sr_decay_rate = get_sr_decay_rate(cpi, next_frame); - const double zero_motion_factor = - (0.95 * pow((next_frame->pcnt_inter - next_frame->pcnt_motion), - ZM_POWER_FACTOR)); - - return AOMMAX(zero_motion_factor, - (sr_decay_rate + ((1.0 - sr_decay_rate) * zero_motion_factor))); -} - -// Function to test for a condition where a complex transition is followed -// by a static section. For example in slide shows where there is a fade -// between slides. This is to help with more optimal kf and gf positioning. -static int detect_transition_to_still(AV1_COMP *cpi, int frame_interval, - int still_interval, - double loop_decay_rate, - double last_decay_rate) { - TWO_PASS *const twopass = &cpi->twopass; - RATE_CONTROL *const rc = &cpi->rc; - - // Break clause to detect very still sections after motion - // For example a static image after a fade or other transition - // instead of a clean scene cut. - if (frame_interval > rc->min_gf_interval && loop_decay_rate >= 0.999 && - last_decay_rate < 0.9) { - int j; - - // Look ahead a few frames to see if static condition persists... - for (j = 0; j < still_interval; ++j) { - const FIRSTPASS_STATS *stats = &twopass->stats_in[j]; - if (stats >= twopass->stats_in_end) break; - - if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break; - } - - // Only if it does do we signal a transition to still. - return j == still_interval; - } - - return 0; -} - -// This function detects a flash through the high relative pcnt_second_ref -// score in the frame following a flash frame. The offset passed in should -// reflect this. -static int detect_flash(const TWO_PASS *twopass, int offset) { - const FIRSTPASS_STATS *const next_frame = read_frame_stats(twopass, offset); - - // What we are looking for here is a situation where there is a - // brief break in prediction (such as a flash) but subsequent frames - // are reasonably well predicted by an earlier (pre flash) frame. - // The recovery after a flash is indicated by a high pcnt_second_ref - // compared to pcnt_inter. - return next_frame != NULL && - next_frame->pcnt_second_ref > next_frame->pcnt_inter && - next_frame->pcnt_second_ref >= 0.5; -} - -// Update the motion related elements to the GF arf boost calculation. -static void accumulate_frame_motion_stats(const FIRSTPASS_STATS *stats, - double *mv_in_out, - double *mv_in_out_accumulator, - double *abs_mv_in_out_accumulator, - double *mv_ratio_accumulator) { - const double pct = stats->pcnt_motion; - - // Accumulate Motion In/Out of frame stats. - *mv_in_out = stats->mv_in_out_count * pct; - *mv_in_out_accumulator += *mv_in_out; - *abs_mv_in_out_accumulator += fabs(*mv_in_out); - - // Accumulate a measure of how uniform (or conversely how random) the motion - // field is (a ratio of abs(mv) / mv). - if (pct > 0.05) { - const double mvr_ratio = - fabs(stats->mvr_abs) / DOUBLE_DIVIDE_CHECK(fabs(stats->MVr)); - const double mvc_ratio = - fabs(stats->mvc_abs) / DOUBLE_DIVIDE_CHECK(fabs(stats->MVc)); - - *mv_ratio_accumulator += - pct * (mvr_ratio < stats->mvr_abs ? mvr_ratio : stats->mvr_abs); - *mv_ratio_accumulator += - pct * (mvc_ratio < stats->mvc_abs ? mvc_ratio : stats->mvc_abs); - } -} - -#define BASELINE_ERR_PER_MB 1000.0 -static double calc_frame_boost(AV1_COMP *cpi, const FIRSTPASS_STATS *this_frame, - double this_frame_mv_in_out, double max_boost) { - double frame_boost; - const double lq = av1_convert_qindex_to_q( - cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.seq_params.bit_depth); - const double boost_q_correction = AOMMIN((0.5 + (lq * 0.015)), 1.5); - int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs - : cpi->common.MBs; - - // Correct for any inactive region in the image - num_mbs = (int)AOMMAX(1, num_mbs * calculate_active_area(cpi, this_frame)); - - // Underlying boost factor is based on inter error ratio. - frame_boost = (BASELINE_ERR_PER_MB * num_mbs) / - DOUBLE_DIVIDE_CHECK(this_frame->coded_error); - frame_boost = frame_boost * BOOST_FACTOR * boost_q_correction; - - // Increase boost for frames where new data coming into frame (e.g. zoom out). - // Slightly reduce boost if there is a net balance of motion out of the frame - // (zoom in). The range for this_frame_mv_in_out is -1.0 to +1.0. - if (this_frame_mv_in_out > 0.0) - frame_boost += frame_boost * (this_frame_mv_in_out * 2.0); - // In the extreme case the boost is halved. - else - frame_boost += frame_boost * (this_frame_mv_in_out / 2.0); - - return AOMMIN(frame_boost, max_boost * boost_q_correction); -} - -static int calc_arf_boost(AV1_COMP *cpi, int offset, int f_frames, int b_frames, - int *f_boost, int *b_boost) { - TWO_PASS *const twopass = &cpi->twopass; - int i; - double boost_score = 0.0; - double mv_ratio_accumulator = 0.0; - double decay_accumulator = 1.0; - double this_frame_mv_in_out = 0.0; - double mv_in_out_accumulator = 0.0; - double abs_mv_in_out_accumulator = 0.0; - int arf_boost; - int flash_detected = 0; - - // Search forward from the proposed arf/next gf position. - for (i = 0; i < f_frames; ++i) { - const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset); - if (this_frame == NULL) break; - - // Update the motion related elements to the boost calculation. - accumulate_frame_motion_stats( - this_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, - &abs_mv_in_out_accumulator, &mv_ratio_accumulator); - - // We want to discount the flash frame itself and the recovery - // frame that follows as both will have poor scores. - flash_detected = detect_flash(twopass, i + offset) || - detect_flash(twopass, i + offset + 1); - - // Accumulate the effect of prediction quality decay. - if (!flash_detected) { - decay_accumulator *= get_prediction_decay_rate(cpi, this_frame); - decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR - ? MIN_DECAY_FACTOR - : decay_accumulator; - } - - boost_score += - decay_accumulator * - calc_frame_boost(cpi, this_frame, this_frame_mv_in_out, GF_MAX_BOOST); - } - - *f_boost = (int)boost_score; - - // Reset for backward looking loop. - boost_score = 0.0; - mv_ratio_accumulator = 0.0; - decay_accumulator = 1.0; - this_frame_mv_in_out = 0.0; - mv_in_out_accumulator = 0.0; - abs_mv_in_out_accumulator = 0.0; - - // Search backward towards last gf position. - for (i = -1; i >= -b_frames; --i) { - const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset); - if (this_frame == NULL) break; - - // Update the motion related elements to the boost calculation. - accumulate_frame_motion_stats( - this_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, - &abs_mv_in_out_accumulator, &mv_ratio_accumulator); - - // We want to discount the the flash frame itself and the recovery - // frame that follows as both will have poor scores. - flash_detected = detect_flash(twopass, i + offset) || - detect_flash(twopass, i + offset + 1); - - // Cumulative effect of prediction quality decay. - if (!flash_detected) { - decay_accumulator *= get_prediction_decay_rate(cpi, this_frame); - decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR - ? MIN_DECAY_FACTOR - : decay_accumulator; - } - - boost_score += - decay_accumulator * - calc_frame_boost(cpi, this_frame, this_frame_mv_in_out, GF_MAX_BOOST); - } - *b_boost = (int)boost_score; - - arf_boost = (*f_boost + *b_boost); - if (arf_boost < ((b_frames + f_frames) * 20)) - arf_boost = ((b_frames + f_frames) * 20); - arf_boost = AOMMAX(arf_boost, MIN_ARF_GF_BOOST); - - return arf_boost; -} - -// Calculate a section intra ratio used in setting max loop filter. -static int calculate_section_intra_ratio(const FIRSTPASS_STATS *begin, - const FIRSTPASS_STATS *end, - int section_length) { - const FIRSTPASS_STATS *s = begin; - double intra_error = 0.0; - double coded_error = 0.0; - int i = 0; - - while (s < end && i < section_length) { - intra_error += s->intra_error; - coded_error += s->coded_error; - ++s; - ++i; - } - - return (int)(intra_error / DOUBLE_DIVIDE_CHECK(coded_error)); -} - -// Calculate the total bits to allocate in this GF/ARF group. -static int64_t calculate_total_gf_group_bits(AV1_COMP *cpi, - double gf_group_err) { - const RATE_CONTROL *const rc = &cpi->rc; - const TWO_PASS *const twopass = &cpi->twopass; - const int max_bits = frame_max_bits(rc, &cpi->oxcf); - int64_t total_group_bits; - - // Calculate the bits to be allocated to the group as a whole. - if ((twopass->kf_group_bits > 0) && (twopass->kf_group_error_left > 0)) { - total_group_bits = (int64_t)(twopass->kf_group_bits * - (gf_group_err / twopass->kf_group_error_left)); - } else { - total_group_bits = 0; - } - - // Clamp odd edge cases. - total_group_bits = (total_group_bits < 0) - ? 0 - : (total_group_bits > twopass->kf_group_bits) - ? twopass->kf_group_bits - : total_group_bits; - - // Clip based on user supplied data rate variability limit. - if (total_group_bits > (int64_t)max_bits * rc->baseline_gf_interval) - total_group_bits = (int64_t)max_bits * rc->baseline_gf_interval; - - return total_group_bits; -} - -// Calculate the number bits extra to assign to boosted frames in a group. -static int calculate_boost_bits(int frame_count, int boost, - int64_t total_group_bits) { - int allocation_chunks; - - // return 0 for invalid inputs (could arise e.g. through rounding errors) - if (!boost || (total_group_bits <= 0) || (frame_count <= 0)) return 0; - - allocation_chunks = (frame_count * 100) + boost; - - // Prevent overflow. - if (boost > 1023) { - int divisor = boost >> 10; - boost /= divisor; - allocation_chunks /= divisor; - } - - // Calculate the number of extra bits for use in the boosted frame or frames. - return AOMMAX((int)(((int64_t)boost * total_group_bits) / allocation_chunks), - 0); -} - -// #define CHCEK_GF_PARAMETER -#ifdef CHCEK_GF_PARAMETER -void check_frame_params(GF_GROUP *const gf_group, int gf_interval, - int frame_nums) { - static const char *update_type_strings[] = { - "KF_UPDATE", "LF_UPDATE", "GF_UPDATE", - "ARF_UPDATE", "OVERLAY_UPDATE", "BRF_UPDATE", - "LAST_BIPRED_UPDATE", "BIPRED_UPDATE", "INTNL_OVERLAY_UPDATE", - "INTNL_ARF_UPDATE" - }; - FILE *fid = fopen("GF_PARAMS.txt", "a"); - - fprintf(fid, "\n{%d}\n", gf_interval); - for (int i = 0; i <= frame_nums; ++i) { - fprintf(fid, "%s %d %d %d %d\n", - update_type_strings[gf_group->update_type[i]], - gf_group->arf_src_offset[i], gf_group->arf_pos_in_gf[i], - gf_group->arf_update_idx[i], gf_group->pyramid_level[i]); - } - - fprintf(fid, "number of nodes in each level: \n"); - for (int i = 0; i < gf_group->pyramid_height; ++i) { - fprintf(fid, "lvl %d: %d ", i, gf_group->pyramid_lvl_nodes[i]); - } - fprintf(fid, "\n"); - fclose(fid); -} -#endif // CHCEK_GF_PARAMETER -static int update_type_2_rf_level(FRAME_UPDATE_TYPE update_type) { - // Derive rf_level from update_type - switch (update_type) { - case LF_UPDATE: return INTER_NORMAL; - case ARF_UPDATE: return GF_ARF_STD; - case OVERLAY_UPDATE: return INTER_NORMAL; - case BRF_UPDATE: return GF_ARF_LOW; - case LAST_BIPRED_UPDATE: return INTER_NORMAL; - case BIPRED_UPDATE: return INTER_NORMAL; - case INTNL_ARF_UPDATE: return GF_ARF_LOW; - case INTNL_OVERLAY_UPDATE: return INTER_NORMAL; - default: return INTER_NORMAL; - } -} - -static void set_multi_layer_params(GF_GROUP *const gf_group, int l, int r, - int *frame_ind, int arf_ind, int level) { - if (r - l < 4) { - while (++l < r) { - // leaf nodes, not a look-ahead frame - gf_group->update_type[*frame_ind] = LF_UPDATE; - gf_group->arf_src_offset[*frame_ind] = 0; - gf_group->arf_pos_in_gf[*frame_ind] = 0; - gf_group->arf_update_idx[*frame_ind] = arf_ind; - gf_group->pyramid_level[*frame_ind] = 0; - ++gf_group->pyramid_lvl_nodes[0]; - ++(*frame_ind); - } - } else { - int m = (l + r) / 2; - int arf_pos_in_gf = *frame_ind; - - gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE; - gf_group->arf_src_offset[*frame_ind] = m - l - 1; - gf_group->arf_pos_in_gf[*frame_ind] = 0; - gf_group->arf_update_idx[*frame_ind] = 1; // mark all internal ARF 1 - gf_group->pyramid_level[*frame_ind] = level; - ++gf_group->pyramid_lvl_nodes[level]; - ++(*frame_ind); - - // set parameters for frames displayed before this frame - set_multi_layer_params(gf_group, l, m, frame_ind, 1, level - 1); - - // for overlay frames, we need to record the position of its corresponding - // arf frames for bit allocation - gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE; - gf_group->arf_src_offset[*frame_ind] = 0; - gf_group->arf_pos_in_gf[*frame_ind] = arf_pos_in_gf; - gf_group->arf_update_idx[*frame_ind] = 1; - gf_group->pyramid_level[*frame_ind] = 0; - ++(*frame_ind); - - // set parameters for frames displayed after this frame - set_multi_layer_params(gf_group, m, r, frame_ind, arf_ind, level - 1); - } -} - -static INLINE unsigned char get_pyramid_height(int pyramid_width) { - assert(pyramid_width <= MAX_GF_INTERVAL && pyramid_width >= MIN_GF_INTERVAL && - "invalid gf interval for pyramid structure"); - - return pyramid_width > 12 ? 4 : (pyramid_width > 6 ? 3 : 2); -} - -static int construct_multi_layer_gf_structure(GF_GROUP *const gf_group, - const int gf_interval) { - int frame_index = 0; - gf_group->pyramid_height = get_pyramid_height(gf_interval); - - assert(gf_group->pyramid_height <= MAX_PYRAMID_LVL); - - av1_zero_array(gf_group->pyramid_lvl_nodes, MAX_PYRAMID_LVL); - - // At the beginning of each GF group it will be a key or overlay frame, - gf_group->update_type[frame_index] = OVERLAY_UPDATE; - gf_group->arf_src_offset[frame_index] = 0; - gf_group->arf_pos_in_gf[frame_index] = 0; - gf_group->arf_update_idx[frame_index] = 0; - gf_group->pyramid_level[frame_index] = 0; - ++frame_index; - - // ALT0 - gf_group->update_type[frame_index] = ARF_UPDATE; - gf_group->arf_src_offset[frame_index] = gf_interval - 1; - gf_group->arf_pos_in_gf[frame_index] = 0; - gf_group->arf_update_idx[frame_index] = 0; - gf_group->pyramid_level[frame_index] = gf_group->pyramid_height; - ++frame_index; - - // set parameters for the rest of the frames - set_multi_layer_params(gf_group, 0, gf_interval, &frame_index, 0, - gf_group->pyramid_height - 1); - return frame_index; -} - -// Given the maximum allowed height of the pyramid structure, return the maximum -// GF length supported by the same. -static INLINE int get_max_gf_length(int max_pyr_height) { - // We allow a frame to have at most two left/right descendants before changing - // them into to a subtree, i.e., we allow the following structure: - /* OUT_OF_ORDER_FRAME - / / \ \ - (two left children) F F F F (two right children) */ - // For example, the max gf size supported by 4 layer structure is: - // 1 (KEY/OVERLAY) + 1 + 2 + 4 + 16 (two children on both side of their - // parent) - switch (max_pyr_height) { - case 2: return 6; // = 1 (KEY/OVERLAY) + 1 + 4 - case 3: return 12; // = 1 (KEY/OVERLAY) + 1 + 2 + 8 - case 4: return 24; // = 1 (KEY/OVERLAY) + 1 + 2 + 4 + 16 - case 1: - return MAX_GF_INTERVAL; // Special case: uses the old pyramid structure. - default: assert(0 && "Invalid max_pyr_height"); return -1; - } -} - -// Given the maximum allowed height of the pyramid structure, return the fixed -// GF length to be used. -int av1_rc_get_fixed_gf_length(int max_pyr_height) { - const int max_gf_length_allowed = get_max_gf_length(max_pyr_height); - return AOMMIN(max_gf_length_allowed, MAX_GF_INTERVAL); -} - -static void define_customized_gf_group_structure( - AV1_COMP *cpi, const EncodeFrameParams *const frame_params) { - RATE_CONTROL *const rc = &cpi->rc; - TWO_PASS *const twopass = &cpi->twopass; - GF_GROUP *const gf_group = &twopass->gf_group; - const int key_frame = frame_params->frame_type == KEY_FRAME; - - assert(rc->baseline_gf_interval >= MIN_GF_INTERVAL && - rc->baseline_gf_interval <= - get_max_gf_length(cpi->oxcf.gf_max_pyr_height)); - assert(cpi->oxcf.gf_max_pyr_height >= MIN_PYRAMID_LVL && - cpi->oxcf.gf_max_pyr_height <= MAX_PYRAMID_LVL); - - const int gf_update_frames = - construct_multi_layer_gf_structure(gf_group, rc->baseline_gf_interval); - int frame_index; - - cpi->num_extra_arfs = 0; - - for (frame_index = 0; frame_index < gf_update_frames; ++frame_index) { - // Set unused variables to default values - gf_group->bidir_pred_enabled[frame_index] = 0; - gf_group->brf_src_offset[frame_index] = 0; - - // Special handle for the first frame for assigning update_type - if (frame_index == 0) { - // For key frames the frame target rate is already set and it - // is also the golden frame. - if (key_frame) { - gf_group->update_type[frame_index] = KF_UPDATE; - continue; - } - - if (rc->source_alt_ref_active) { - gf_group->update_type[frame_index] = OVERLAY_UPDATE; - } else { - gf_group->update_type[frame_index] = GF_UPDATE; - } - } else { - if (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) - ++cpi->num_extra_arfs; - } - - // Assign rf level based on update type - gf_group->rf_level[frame_index] = - update_type_2_rf_level(gf_group->update_type[frame_index]); - } - - // NOTE: We need to configure the frame at the end of the sequence + 1 that - // will be the start frame for the next group. Otherwise prior to the - // call to av1_rc_get_second_pass_params() the data will be undefined. - if (rc->source_alt_ref_pending) { - gf_group->update_type[frame_index] = OVERLAY_UPDATE; - gf_group->rf_level[frame_index] = INTER_NORMAL; - } else { - gf_group->update_type[frame_index] = GF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_STD; - } - - gf_group->bidir_pred_enabled[frame_index] = 0; - gf_group->brf_src_offset[frame_index] = 0; - gf_group->arf_update_idx[frame_index] = 0; - // This value is only used for INTNL_OVERLAY_UPDATE - gf_group->arf_pos_in_gf[frame_index] = 0; - - // This parameter is useless? - gf_group->arf_ref_idx[frame_index] = 0; -#ifdef CHCEK_GF_PARAMETER - check_frame_params(gf_group, rc->baseline_gf_interval, gf_update_frames); -#endif -} - -// It is an example of how to define a GF stucture manually. The function will -// result in exactly the same GF group structure as -// define_customized_gf_group_structure() when rc->baseline_gf_interval == 4 - -static void define_gf_group_structure( - AV1_COMP *cpi, const EncodeFrameParams *const frame_params) { - RATE_CONTROL *const rc = &cpi->rc; - - const int max_pyr_height = cpi->oxcf.gf_max_pyr_height; - const int valid_customized_gf_length = - max_pyr_height >= MIN_PYRAMID_LVL && max_pyr_height <= MAX_PYRAMID_LVL && - rc->baseline_gf_interval >= MIN_GF_INTERVAL && - rc->baseline_gf_interval <= get_max_gf_length(max_pyr_height); - // used the new structure only if extra_arf is allowed - if (valid_customized_gf_length && rc->source_alt_ref_pending && - cpi->extra_arf_allowed > 0) { - define_customized_gf_group_structure(cpi, frame_params); - cpi->new_bwdref_update_rule = 1; - return; - } else { - cpi->new_bwdref_update_rule = 0; - } - - TWO_PASS *const twopass = &cpi->twopass; - GF_GROUP *const gf_group = &twopass->gf_group; - int i; - int frame_index = 0; - const int key_frame = frame_params->frame_type == KEY_FRAME; - - // The use of bi-predictive frames are only enabled when following 3 - // conditions are met: - // (1) ALTREF is enabled; - // (2) The bi-predictive group interval is at least 2; and - // (3) The bi-predictive group interval is strictly smaller than the - // golden group interval. - const int is_bipred_enabled = - cpi->extra_arf_allowed && rc->source_alt_ref_pending && - rc->bipred_group_interval && - rc->bipred_group_interval <= - (rc->baseline_gf_interval - rc->source_alt_ref_pending); - int bipred_group_end = 0; - int bipred_frame_index = 0; - - const unsigned char ext_arf_interval = - (unsigned char)(rc->baseline_gf_interval / (cpi->num_extra_arfs + 1) - 1); - int which_arf = cpi->num_extra_arfs; - int subgroup_interval[MAX_EXT_ARFS + 1]; - int is_sg_bipred_enabled = is_bipred_enabled; - int accumulative_subgroup_interval = 0; - - // For key frames the frame target rate is already set and it - // is also the golden frame. - // === [frame_index == 0] === - if (!key_frame) { - if (rc->source_alt_ref_active) { - gf_group->update_type[frame_index] = OVERLAY_UPDATE; - gf_group->rf_level[frame_index] = INTER_NORMAL; - } else { - gf_group->update_type[frame_index] = GF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_STD; - } - gf_group->arf_update_idx[frame_index] = 0; - gf_group->arf_ref_idx[frame_index] = 0; - } - - gf_group->bidir_pred_enabled[frame_index] = 0; - gf_group->brf_src_offset[frame_index] = 0; - - frame_index++; - - bipred_frame_index++; - - // === [frame_index == 1] === - if (rc->source_alt_ref_pending) { - gf_group->update_type[frame_index] = ARF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_STD; - gf_group->arf_src_offset[frame_index] = - (unsigned char)(rc->baseline_gf_interval - 1); - - gf_group->arf_update_idx[frame_index] = 0; - gf_group->arf_ref_idx[frame_index] = 0; - - gf_group->bidir_pred_enabled[frame_index] = 0; - gf_group->brf_src_offset[frame_index] = 0; - // NOTE: "bidir_pred_frame_index" stays unchanged for ARF_UPDATE frames. - - // Work out the ARFs' positions in this gf group - // NOTE(weitinglin): ALT_REFs' are indexed inversely, but coded in display - // order (except for the original ARF). In the example of three ALT_REF's, - // We index ALTREF's as: KEY ----- ALT2 ----- ALT1 ----- ALT0 - // but code them in the following order: - // KEY-ALT0-ALT2 ----- OVERLAY2-ALT1 ----- OVERLAY1 ----- OVERLAY0 - // - // arf_pos_for_ovrly[]: Position for OVERLAY - // arf_pos_in_gf[]: Position for ALTREF - cpi->arf_pos_for_ovrly[0] = frame_index + cpi->num_extra_arfs + - gf_group->arf_src_offset[frame_index] + 1; - for (i = 0; i < cpi->num_extra_arfs; ++i) { - cpi->arf_pos_for_ovrly[i + 1] = - frame_index + (cpi->num_extra_arfs - i) * (ext_arf_interval + 2); - subgroup_interval[i] = cpi->arf_pos_for_ovrly[i] - - cpi->arf_pos_for_ovrly[i + 1] - (i == 0 ? 1 : 2); - } - subgroup_interval[cpi->num_extra_arfs] = - cpi->arf_pos_for_ovrly[cpi->num_extra_arfs] - frame_index - - (cpi->num_extra_arfs == 0 ? 1 : 2); - - ++frame_index; - - // Insert an extra ARF - // === [frame_index == 2] === - if (cpi->num_extra_arfs) { - gf_group->update_type[frame_index] = INTNL_ARF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_LOW; - gf_group->arf_src_offset[frame_index] = ext_arf_interval; - - gf_group->arf_update_idx[frame_index] = which_arf; - gf_group->arf_ref_idx[frame_index] = 0; - ++frame_index; - } - accumulative_subgroup_interval += subgroup_interval[cpi->num_extra_arfs]; - } - - const int normal_frames = - rc->baseline_gf_interval - (key_frame || rc->source_alt_ref_pending); - - for (i = 0; i < normal_frames; ++i) { - gf_group->arf_update_idx[frame_index] = which_arf; - gf_group->arf_ref_idx[frame_index] = which_arf; - - // If we are going to have ARFs, check whether we can have BWDREF in this - // subgroup, and further, whether we can have ARF subgroup which contains - // the BWDREF subgroup but contained within the GF group: - // - // GF group --> ARF subgroup --> BWDREF subgroup - if (rc->source_alt_ref_pending) { - is_sg_bipred_enabled = - is_bipred_enabled && - (subgroup_interval[which_arf] > rc->bipred_group_interval); - } - - // NOTE: BIDIR_PRED is only enabled when the length of the bi-predictive - // frame group interval is strictly smaller than that of the GOLDEN - // FRAME group interval. - // TODO(zoeliu): Currently BIDIR_PRED is only enabled when alt-ref is on. - if (is_sg_bipred_enabled && !bipred_group_end) { - const int cur_brf_src_offset = rc->bipred_group_interval - 1; - - if (bipred_frame_index == 1) { - // --- BRF_UPDATE --- - gf_group->update_type[frame_index] = BRF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_LOW; - gf_group->brf_src_offset[frame_index] = cur_brf_src_offset; - } else if (bipred_frame_index == rc->bipred_group_interval) { - // --- LAST_BIPRED_UPDATE --- - gf_group->update_type[frame_index] = LAST_BIPRED_UPDATE; - gf_group->rf_level[frame_index] = INTER_NORMAL; - gf_group->brf_src_offset[frame_index] = 0; - - // Reset the bi-predictive frame index. - bipred_frame_index = 0; - } else { - // --- BIPRED_UPDATE --- - gf_group->update_type[frame_index] = BIPRED_UPDATE; - gf_group->rf_level[frame_index] = INTER_NORMAL; - gf_group->brf_src_offset[frame_index] = 0; - } - gf_group->bidir_pred_enabled[frame_index] = 1; - - bipred_frame_index++; - // Check whether the next bi-predictive frame group would entirely be - // included within the current golden frame group. - // In addition, we need to avoid coding a BRF right before an ARF. - if (bipred_frame_index == 1 && - (i + 2 + cur_brf_src_offset) >= accumulative_subgroup_interval) { - bipred_group_end = 1; - } - } else { - gf_group->update_type[frame_index] = LF_UPDATE; - gf_group->rf_level[frame_index] = INTER_NORMAL; - gf_group->bidir_pred_enabled[frame_index] = 0; - gf_group->brf_src_offset[frame_index] = 0; - } - - ++frame_index; - - // Check if we need to update the ARF. - if (is_sg_bipred_enabled && cpi->num_extra_arfs && which_arf > 0 && - frame_index > cpi->arf_pos_for_ovrly[which_arf]) { - --which_arf; - accumulative_subgroup_interval += subgroup_interval[which_arf] + 1; - - // Meet the new subgroup; Reset the bipred_group_end flag. - bipred_group_end = 0; - // Insert another extra ARF after the overlay frame - if (which_arf) { - gf_group->update_type[frame_index] = INTNL_ARF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_LOW; - gf_group->arf_src_offset[frame_index] = ext_arf_interval; - - gf_group->arf_update_idx[frame_index] = which_arf; - gf_group->arf_ref_idx[frame_index] = 0; - ++frame_index; - } - } - } - - // NOTE: We need to configure the frame at the end of the sequence + 1 that - // will be the start frame for the next group. Otherwise prior to the - // call to av1_rc_get_second_pass_params() the data will be undefined. - gf_group->arf_update_idx[frame_index] = 0; - gf_group->arf_ref_idx[frame_index] = 0; - - if (rc->source_alt_ref_pending) { - gf_group->update_type[frame_index] = OVERLAY_UPDATE; - gf_group->rf_level[frame_index] = INTER_NORMAL; - - cpi->arf_pos_in_gf[0] = 1; - if (cpi->num_extra_arfs) { - // Overwrite the update_type for extra-ARF's corresponding internal - // OVERLAY's: Change from LF_UPDATE to INTNL_OVERLAY_UPDATE. - for (i = cpi->num_extra_arfs; i > 0; --i) { - cpi->arf_pos_in_gf[i] = - (i == cpi->num_extra_arfs ? 2 : cpi->arf_pos_for_ovrly[i + 1] + 1); - - gf_group->update_type[cpi->arf_pos_for_ovrly[i]] = INTNL_OVERLAY_UPDATE; - gf_group->rf_level[cpi->arf_pos_for_ovrly[i]] = INTER_NORMAL; - } - } - } else { - gf_group->update_type[frame_index] = GF_UPDATE; - gf_group->rf_level[frame_index] = GF_ARF_STD; - } - - gf_group->bidir_pred_enabled[frame_index] = 0; - gf_group->brf_src_offset[frame_index] = 0; -} - -#define LEAF_REDUCTION_FACTOR 0.75 -static double lvl_budget_factor[MAX_PYRAMID_LVL - 1][MAX_PYRAMID_LVL - 1] = { - { 1.0, 0.0, 0.0 }, { 0.6, 0.4, 0 }, { 0.45, 0.35, 0.20 } -}; -static void allocate_gf_group_bits( - AV1_COMP *cpi, int64_t gf_group_bits, double group_error, int gf_arf_bits, - const EncodeFrameParams *const frame_params) { - RATE_CONTROL *const rc = &cpi->rc; - const AV1EncoderConfig *const oxcf = &cpi->oxcf; - TWO_PASS *const twopass = &cpi->twopass; - GF_GROUP *const gf_group = &twopass->gf_group; - int i; - int frame_index = 0; - const int key_frame = frame_params->frame_type == KEY_FRAME; - const int max_bits = frame_max_bits(&cpi->rc, &cpi->oxcf); - int64_t total_group_bits = gf_group_bits; - int ext_arf_boost[MAX_EXT_ARFS]; - - define_gf_group_structure(cpi, frame_params); - - av1_zero_array(ext_arf_boost, MAX_EXT_ARFS); - - // For key frames the frame target rate is already set and it - // is also the golden frame. - // === [frame_index == 0] === - if (!key_frame) { - if (rc->source_alt_ref_active) - gf_group->bit_allocation[frame_index] = 0; - else - gf_group->bit_allocation[frame_index] = gf_arf_bits; - - // Step over the golden frame / overlay frame - FIRSTPASS_STATS frame_stats; - if (EOF == input_stats(twopass, &frame_stats)) return; - } - - // Deduct the boost bits for arf (or gf if it is not a key frame) - // from the group total. - if (rc->source_alt_ref_pending || !key_frame) total_group_bits -= gf_arf_bits; - - frame_index++; - - // Store the bits to spend on the ARF if there is one. - // === [frame_index == 1] === - if (rc->source_alt_ref_pending) { - gf_group->bit_allocation[frame_index] = gf_arf_bits; - - ++frame_index; - - // Skip all the extra-ARF's right after ARF at the starting segment of - // the current GF group. - if (cpi->num_extra_arfs) { - while (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) - ++frame_index; - } - } - - // Save. - const int tmp_frame_index = frame_index; - int budget_reduced_from_leaf_level = 0; - - // Allocate bits to the other frames in the group. - const int normal_frames = - rc->baseline_gf_interval - (key_frame || rc->source_alt_ref_pending); - - for (i = 0; i < normal_frames; ++i) { - FIRSTPASS_STATS frame_stats; - if (EOF == input_stats(twopass, &frame_stats)) break; - - const double modified_err = - calculate_modified_err(cpi, twopass, oxcf, &frame_stats); - const double err_fraction = - (group_error > 0) ? modified_err / DOUBLE_DIVIDE_CHECK(group_error) - : 0.0; - const int target_frame_size = - clamp((int)((double)total_group_bits * err_fraction), 0, - AOMMIN(max_bits, (int)total_group_bits)); - - if (gf_group->update_type[frame_index] == BRF_UPDATE) { - // Boost up the allocated bits on BWDREF_FRAME - gf_group->bit_allocation[frame_index] = - target_frame_size + (target_frame_size >> 2); - } else if (gf_group->update_type[frame_index] == LAST_BIPRED_UPDATE) { - // Press down the allocated bits on LAST_BIPRED_UPDATE frames - gf_group->bit_allocation[frame_index] = - target_frame_size - (target_frame_size >> 1); - } else if (gf_group->update_type[frame_index] == BIPRED_UPDATE) { - // TODO(zoeliu): To investigate whether the allocated bits on - // BIPRED_UPDATE frames need to be further adjusted. - gf_group->bit_allocation[frame_index] = target_frame_size; - } else if (cpi->new_bwdref_update_rule && - gf_group->update_type[frame_index] == INTNL_OVERLAY_UPDATE) { - assert(gf_group->pyramid_height <= MAX_PYRAMID_LVL && - "non-valid height for a pyramid structure"); - - const int arf_pos = gf_group->arf_pos_in_gf[frame_index]; - gf_group->bit_allocation[frame_index] = 0; - - gf_group->bit_allocation[arf_pos] = target_frame_size; - // Note: Boost, if needed, is added in the next loop. - } else { - assert(gf_group->update_type[frame_index] == LF_UPDATE || - gf_group->update_type[frame_index] == INTNL_OVERLAY_UPDATE); - gf_group->bit_allocation[frame_index] = target_frame_size; - if (cpi->new_bwdref_update_rule) { - const int this_budget_reduction = - (int)(target_frame_size * LEAF_REDUCTION_FACTOR); - gf_group->bit_allocation[frame_index] -= this_budget_reduction; - budget_reduced_from_leaf_level += this_budget_reduction; - } - } - - ++frame_index; - - // Skip all the extra-ARF's. - if (cpi->num_extra_arfs) { - while (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) - ++frame_index; - } - } - - if (budget_reduced_from_leaf_level > 0) { - // Restore. - frame_index = tmp_frame_index; - - // Re-distribute this extra budget to overlay frames in the group. - for (i = 0; i < normal_frames; ++i) { - if (cpi->new_bwdref_update_rule && - gf_group->update_type[frame_index] == INTNL_OVERLAY_UPDATE) { - assert(gf_group->pyramid_height <= MAX_PYRAMID_LVL && - "non-valid height for a pyramid structure"); - const int arf_pos = gf_group->arf_pos_in_gf[frame_index]; - const int this_lvl = gf_group->pyramid_level[arf_pos]; - const int dist2top = gf_group->pyramid_height - 1 - this_lvl; - const double lvl_boost_factor = - lvl_budget_factor[gf_group->pyramid_height - 2][dist2top]; - const int extra_size = - (int)(budget_reduced_from_leaf_level * lvl_boost_factor / - gf_group->pyramid_lvl_nodes[this_lvl]); - gf_group->bit_allocation[arf_pos] += extra_size; - } - ++frame_index; - - // Skip all the extra-ARF's. - if (cpi->num_extra_arfs) { - while (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) - ++frame_index; - } - } - } - - if (cpi->new_bwdref_update_rule == 0 && rc->source_alt_ref_pending) { - if (cpi->num_extra_arfs) { - // NOTE: For bit allocation, move the allocated bits associated with - // INTNL_OVERLAY_UPDATE to the corresponding INTNL_ARF_UPDATE. - // i > 0 for extra-ARF's and i == 0 for ARF: - // arf_pos_for_ovrly[i]: Position for INTNL_OVERLAY_UPDATE - // arf_pos_in_gf[i]: Position for INTNL_ARF_UPDATE - for (i = cpi->num_extra_arfs; i > 0; --i) { - assert(gf_group->update_type[cpi->arf_pos_for_ovrly[i]] == - INTNL_OVERLAY_UPDATE); - - // Encoder's choice: - // Set show_existing_frame == 1 for all extra-ARF's, and hence - // allocate zero bit for both all internal OVERLAY frames. - gf_group->bit_allocation[cpi->arf_pos_in_gf[i]] = - gf_group->bit_allocation[cpi->arf_pos_for_ovrly[i]]; - gf_group->bit_allocation[cpi->arf_pos_for_ovrly[i]] = 0; - } - } - } -} - -// Returns true if KF group and GF group both are almost completely static. -static INLINE int is_almost_static(double gf_zero_motion, int kf_zero_motion) { - return (gf_zero_motion >= 0.995) && - (kf_zero_motion >= STATIC_KF_GROUP_THRESH); -} - -#define ARF_ABS_ZOOM_THRESH 4.4 - -// Analyse and define a gf/arf group. -static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, - const EncodeFrameParams *const frame_params) { - AV1_COMMON *const cm = &cpi->common; - RATE_CONTROL *const rc = &cpi->rc; - AV1EncoderConfig *const oxcf = &cpi->oxcf; - TWO_PASS *const twopass = &cpi->twopass; - FIRSTPASS_STATS next_frame; - const FIRSTPASS_STATS *const start_pos = twopass->stats_in; - int i; - - double boost_score = 0.0; - int active_min_gf_interval; - double gf_group_err = 0.0; -#if GROUP_ADAPTIVE_MAXQ - double gf_group_raw_error = 0.0; -#endif - double gf_group_skip_pct = 0.0; - double gf_group_inactive_zone_rows = 0.0; - double gf_first_frame_err = 0.0; - double mod_frame_err = 0.0; - - double mv_ratio_accumulator = 0.0; - double decay_accumulator = 1.0; - double zero_motion_accumulator = 1.0; - - double loop_decay_rate = 1.00; - double last_loop_decay_rate = 1.00; - - double this_frame_mv_in_out = 0.0; - double mv_in_out_accumulator = 0.0; - double abs_mv_in_out_accumulator = 0.0; - - unsigned int allow_alt_ref = is_altref_enabled(cpi); - - int f_boost = 0; - int b_boost = 0; - int flash_detected; - int64_t gf_group_bits; - double gf_group_error_left; - int gf_arf_bits; - const int is_intra_only = frame_params->frame_type == KEY_FRAME || - frame_params->frame_type == INTRA_ONLY_FRAME; - const int arf_active_or_kf = is_intra_only || rc->source_alt_ref_active; - - cpi->extra_arf_allowed = 1; - - // Reset the GF group data structures unless this is a key - // frame in which case it will already have been done. - if (!is_intra_only) { - av1_zero(twopass->gf_group); - } - - aom_clear_system_state(); - av1_zero(next_frame); - - // Load stats for the current frame. - mod_frame_err = calculate_modified_err(cpi, twopass, oxcf, this_frame); - - // Note the error of the frame at the start of the group. This will be - // the GF frame error if we code a normal gf. - gf_first_frame_err = mod_frame_err; - - // If this is a key frame or the overlay from a previous arf then - // the error score / cost of this frame has already been accounted for. - if (arf_active_or_kf) { - gf_group_err -= gf_first_frame_err; -#if GROUP_ADAPTIVE_MAXQ - gf_group_raw_error -= this_frame->coded_error; -#endif - gf_group_skip_pct -= this_frame->intra_skip_pct; - gf_group_inactive_zone_rows -= this_frame->inactive_zone_rows; - } - // Motion breakout threshold for loop below depends on image size. - const double mv_ratio_accumulator_thresh = - (cpi->initial_height + cpi->initial_width) / 4.0; - - // TODO(urvang): Try logic to vary min and max interval based on q. - active_min_gf_interval = rc->min_gf_interval; - - double avg_sr_coded_error = 0; - double avg_raw_err_stdev = 0; - int non_zero_stdev_count = 0; - - i = 0; - while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) { - ++i; - - // Accumulate error score of frames in this gf group. - mod_frame_err = calculate_modified_err(cpi, twopass, oxcf, this_frame); - gf_group_err += mod_frame_err; -#if GROUP_ADAPTIVE_MAXQ - gf_group_raw_error += this_frame->coded_error; -#endif - gf_group_skip_pct += this_frame->intra_skip_pct; - gf_group_inactive_zone_rows += this_frame->inactive_zone_rows; - - if (EOF == input_stats(twopass, &next_frame)) break; - - // Test for the case where there is a brief flash but the prediction - // quality back to an earlier frame is then restored. - flash_detected = detect_flash(twopass, 0); - - // Update the motion related elements to the boost calculation. - accumulate_frame_motion_stats( - &next_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, - &abs_mv_in_out_accumulator, &mv_ratio_accumulator); - // sum up the metric values of current gf group - avg_sr_coded_error += next_frame.sr_coded_error; - if (fabs(next_frame.raw_error_stdev) > 0.000001) { - non_zero_stdev_count++; - avg_raw_err_stdev += next_frame.raw_error_stdev; - } - - // Accumulate the effect of prediction quality decay. - if (!flash_detected) { - last_loop_decay_rate = loop_decay_rate; - loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); - - decay_accumulator = decay_accumulator * loop_decay_rate; - - // Monitor for static sections. - if ((rc->frames_since_key + i - 1) > 1) { - zero_motion_accumulator = AOMMIN( - zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame)); - } - - // Break clause to detect very still sections after motion. For example, - // a static image after a fade or other transition. - if (detect_transition_to_still(cpi, i, 5, loop_decay_rate, - last_loop_decay_rate)) { - allow_alt_ref = 0; - break; - } - } - - // Calculate a boost number for this frame. - boost_score += - decay_accumulator * - calc_frame_boost(cpi, &next_frame, this_frame_mv_in_out, GF_MAX_BOOST); - // If almost totally static, we will not use the the fixed GF length later, - // so we can continue for more frames. - if (i >= (av1_rc_get_fixed_gf_length(oxcf->gf_max_pyr_height) + 1) && - !is_almost_static(zero_motion_accumulator, - twopass->kf_zeromotion_pct)) { - break; - } - - // Some conditions to breakout after min interval. - if (i >= active_min_gf_interval && - // If possible don't break very close to a kf - (rc->frames_to_key - i >= rc->min_gf_interval) && (i & 0x01) && - !flash_detected && - (mv_ratio_accumulator > mv_ratio_accumulator_thresh || - abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH)) { - break; - } - *this_frame = next_frame; - } - twopass->gf_zeromotion_pct = (int)(zero_motion_accumulator * 1000.0); - - // Was the group length constrained by the requirement for a new KF? - rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0; - - const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs - : cpi->common.MBs; - assert(num_mbs > 0); - if (i) avg_sr_coded_error /= i; - - if (non_zero_stdev_count) avg_raw_err_stdev /= non_zero_stdev_count; - - // Disable extra altrefs and backward refs for "still" gf group: - // zero_motion_accumulator: minimum percentage of (0,0) motion; - // avg_sr_coded_error: average of the SSE per pixel of each frame; - // avg_raw_err_stdev: average of the standard deviation of (0,0) - // motion error per block of each frame. - const int disable_bwd_extarf = - (zero_motion_accumulator > MIN_ZERO_MOTION && - avg_sr_coded_error / num_mbs < MAX_SR_CODED_ERROR && - avg_raw_err_stdev < MAX_RAW_ERR_VAR); - - if (disable_bwd_extarf) cpi->extra_arf_allowed = 0; - - const int use_alt_ref = - !is_almost_static(zero_motion_accumulator, twopass->kf_zeromotion_pct) && - allow_alt_ref && (i < cpi->oxcf.lag_in_frames) && - (i >= rc->min_gf_interval); - -#define REDUCE_GF_LENGTH_THRESH 4 -#define REDUCE_GF_LENGTH_TO_KEY_THRESH 9 -#define REDUCE_GF_LENGTH_BY 1 - int alt_offset = 0; - // The length reduction strategy is tweaked using AOM_Q mode, and doesn't work - // for VBR mode. - // Also, we don't have do adjustment for lossless mode. - const int allow_gf_length_reduction = - (cpi->oxcf.rc_mode == AOM_Q || cpi->extra_arf_allowed == 0) && - !is_lossless_requested(&cpi->oxcf); - - if (allow_gf_length_reduction && use_alt_ref) { - // adjust length of this gf group if one of the following condition met - // 1: only one overlay frame left and this gf is too long - // 2: next gf group is too short to have arf compared to the current gf - - // maximum length of next gf group - const int next_gf_len = rc->frames_to_key - i; - const int single_overlay_left = - next_gf_len == 0 && i > REDUCE_GF_LENGTH_THRESH; - // the next gf is probably going to have a ARF but it will be shorter than - // this gf - const int unbalanced_gf = - i > REDUCE_GF_LENGTH_TO_KEY_THRESH && - next_gf_len + 1 < REDUCE_GF_LENGTH_TO_KEY_THRESH && - next_gf_len + 1 >= rc->min_gf_interval; - - if (single_overlay_left || unbalanced_gf) { - // Note: Tried roll_back = DIVIDE_AND_ROUND(i, 8), but is does not work - // better in the current setting - const int roll_back = REDUCE_GF_LENGTH_BY; - alt_offset = -roll_back; - i -= roll_back; - } - } - - // Should we use the alternate reference frame. - if (use_alt_ref) { - // Calculate the boost for alt ref. - rc->gfu_boost = - calc_arf_boost(cpi, alt_offset, (i - 1), (i - 1), &f_boost, &b_boost); - rc->source_alt_ref_pending = 1; - - // do not replace ARFs with overlay frames, and keep it as GOLDEN_REF - cpi->preserve_arf_as_gld = 1; - } else { - rc->gfu_boost = AOMMAX((int)boost_score, MIN_ARF_GF_BOOST); - rc->source_alt_ref_pending = 0; - cpi->preserve_arf_as_gld = 0; - } - - // Set the interval until the next gf. - // If forward keyframes are enabled, ensure the final gf group obeys the - // MIN_FWD_KF_INTERVAL. - if (cpi->oxcf.fwd_kf_enabled && - ((twopass->stats_in - i + rc->frames_to_key) < twopass->stats_in_end)) { - if (i == rc->frames_to_key) { - rc->baseline_gf_interval = i; - // if the last gf group will be smaller than MIN_FWD_KF_INTERVAL - } else if ((rc->frames_to_key - i < - AOMMAX(MIN_FWD_KF_INTERVAL, rc->min_gf_interval)) && - (rc->frames_to_key != i)) { - // if possible, merge the last two gf groups - if (rc->frames_to_key <= get_max_gf_length(oxcf->gf_max_pyr_height)) { - rc->baseline_gf_interval = rc->frames_to_key; - // if merging the last two gf groups creates a group that is too long, - // split them and force the last gf group to be the MIN_FWD_KF_INTERVAL - } else { - rc->baseline_gf_interval = rc->frames_to_key - MIN_FWD_KF_INTERVAL; - } - } else { - rc->baseline_gf_interval = i - rc->source_alt_ref_pending; - } - } else { - rc->baseline_gf_interval = i - rc->source_alt_ref_pending; - } - -#define LAST_ALR_BOOST_FACTOR 0.2f - rc->arf_boost_factor = 1.0; - if (rc->source_alt_ref_pending && !is_lossless_requested(&cpi->oxcf)) { - // Reduce the boost of altref in the last gf group - if (rc->frames_to_key - i == REDUCE_GF_LENGTH_BY || - rc->frames_to_key - i == 0) { - rc->arf_boost_factor = LAST_ALR_BOOST_FACTOR; - } - } - - if (!cpi->extra_arf_allowed) { - cpi->num_extra_arfs = 0; - } else { - // Calculate 'num_extra_arfs' (internal alt-refs) that we are allowed. - // Note: When new pyramid structure is used through - // 'define_customized_gf_group_structure()' function, this value is - // overridden. - if (rc->baseline_gf_interval == MIN_GF_INTERVAL && - rc->source_alt_ref_pending) { - cpi->num_extra_arfs = 1; - } else { - cpi->num_extra_arfs = get_number_of_extra_arfs(rc->baseline_gf_interval, - rc->source_alt_ref_pending, - oxcf->gf_max_pyr_height); - } - } - - rc->frames_till_gf_update_due = rc->baseline_gf_interval; - - rc->bipred_group_interval = BFG_INTERVAL; - // The minimum bi-predictive frame group interval is 2. - if (rc->bipred_group_interval < 2) rc->bipred_group_interval = 0; - - // Reset the file position. - reset_fpf_position(twopass, start_pos); - - // Calculate the bits to be allocated to the gf/arf group as a whole - gf_group_bits = calculate_total_gf_group_bits(cpi, gf_group_err); - -#if GROUP_ADAPTIVE_MAXQ - // Calculate an estimate of the maxq needed for the group. - // We are more agressive about correcting for sections - // where there could be significant overshoot than for easier - // sections where we do not wish to risk creating an overshoot - // of the allocated bit budget. - if ((cpi->oxcf.rc_mode != AOM_Q) && (rc->baseline_gf_interval > 1)) { - const int vbr_group_bits_per_frame = - (int)(gf_group_bits / rc->baseline_gf_interval); - const double group_av_err = gf_group_raw_error / rc->baseline_gf_interval; - const double group_av_skip_pct = - gf_group_skip_pct / rc->baseline_gf_interval; - const double group_av_inactive_zone = - ((gf_group_inactive_zone_rows * 2) / - (rc->baseline_gf_interval * (double)cm->mb_rows)); - - int tmp_q; - // rc factor is a weight factor that corrects for local rate control drift. - double rc_factor = 1.0; - if (rc->rate_error_estimate > 0) { - rc_factor = AOMMAX(RC_FACTOR_MIN, - (double)(100 - rc->rate_error_estimate) / 100.0); - } else { - rc_factor = AOMMIN(RC_FACTOR_MAX, - (double)(100 - rc->rate_error_estimate) / 100.0); - } - tmp_q = get_twopass_worst_quality( - cpi, group_av_err, (group_av_skip_pct + group_av_inactive_zone), - vbr_group_bits_per_frame, twopass->kfgroup_inter_fraction * rc_factor); - twopass->active_worst_quality = - AOMMAX(tmp_q, twopass->active_worst_quality >> 1); - } -#endif - - // Calculate the extra bits to be used for boosted frame(s) - gf_arf_bits = calculate_boost_bits(rc->baseline_gf_interval, rc->gfu_boost, - gf_group_bits); - - // Adjust KF group bits and error remaining. - twopass->kf_group_error_left -= (int64_t)gf_group_err; - - // If this is an arf update we want to remove the score for the overlay - // frame at the end which will usually be very cheap to code. - // The overlay frame has already, in effect, been coded so we want to spread - // the remaining bits among the other frames. - // For normal GFs remove the score for the GF itself unless this is - // also a key frame in which case it has already been accounted for. - if (rc->source_alt_ref_pending) { - gf_group_error_left = gf_group_err - mod_frame_err; - } else if (!is_intra_only) { - gf_group_error_left = gf_group_err - gf_first_frame_err; - } else { - gf_group_error_left = gf_group_err; - } - - // Allocate bits to each of the frames in the GF group. - allocate_gf_group_bits(cpi, gf_group_bits, gf_group_error_left, gf_arf_bits, - frame_params); - - // Reset the file position. - reset_fpf_position(twopass, start_pos); - - // Calculate a section intra ratio used in setting max loop filter. - if (frame_params->frame_type != KEY_FRAME) { - twopass->section_intra_rating = calculate_section_intra_ratio( - start_pos, twopass->stats_in_end, rc->baseline_gf_interval); - } -} - -// Threshold for use of the lagging second reference frame. High second ref -// usage may point to a transient event like a flash or occlusion rather than -// a real scene cut. -#define SECOND_REF_USEAGE_THRESH 0.1 -// Minimum % intra coding observed in first pass (1.0 = 100%) -#define MIN_INTRA_LEVEL 0.25 -// Minimum ratio between the % of intra coding and inter coding in the first -// pass after discounting neutral blocks (discounting neutral blocks in this -// way helps catch scene cuts in clips with very flat areas or letter box -// format clips with image padding. -#define INTRA_VS_INTER_THRESH 2.0 -// Hard threshold where the first pass chooses intra for almost all blocks. -// In such a case even if the frame is not a scene cut coding a key frame -// may be a good option. -#define VERY_LOW_INTER_THRESH 0.05 -// Maximum threshold for the relative ratio of intra error score vs best -// inter error score. -#define KF_II_ERR_THRESHOLD 2.5 -// In real scene cuts there is almost always a sharp change in the intra -// or inter error score. -#define ERR_CHANGE_THRESHOLD 0.4 -// For real scene cuts we expect an improvment in the intra inter error -// ratio in the next frame. -#define II_IMPROVEMENT_THRESHOLD 3.5 -#define KF_II_MAX 128.0 - -static int test_candidate_kf(TWO_PASS *twopass, - const FIRSTPASS_STATS *last_frame, - const FIRSTPASS_STATS *this_frame, - const FIRSTPASS_STATS *next_frame) { - int is_viable_kf = 0; - double pcnt_intra = 1.0 - this_frame->pcnt_inter; - double modified_pcnt_inter = - this_frame->pcnt_inter - this_frame->pcnt_neutral; - - // Does the frame satisfy the primary criteria of a key frame? - // See above for an explanation of the test criteria. - // If so, then examine how well it predicts subsequent frames. - if ((this_frame->pcnt_second_ref < SECOND_REF_USEAGE_THRESH) && - (next_frame->pcnt_second_ref < SECOND_REF_USEAGE_THRESH) && - ((this_frame->pcnt_inter < VERY_LOW_INTER_THRESH) || - ((pcnt_intra > MIN_INTRA_LEVEL) && - (pcnt_intra > (INTRA_VS_INTER_THRESH * modified_pcnt_inter)) && - ((this_frame->intra_error / - DOUBLE_DIVIDE_CHECK(this_frame->coded_error)) < - KF_II_ERR_THRESHOLD) && - ((fabs(last_frame->coded_error - this_frame->coded_error) / - DOUBLE_DIVIDE_CHECK(this_frame->coded_error) > - ERR_CHANGE_THRESHOLD) || - (fabs(last_frame->intra_error - this_frame->intra_error) / - DOUBLE_DIVIDE_CHECK(this_frame->intra_error) > - ERR_CHANGE_THRESHOLD) || - ((next_frame->intra_error / - DOUBLE_DIVIDE_CHECK(next_frame->coded_error)) > - II_IMPROVEMENT_THRESHOLD))))) { - int i; - const FIRSTPASS_STATS *start_pos = twopass->stats_in; - FIRSTPASS_STATS local_next_frame = *next_frame; - double boost_score = 0.0; - double old_boost_score = 0.0; - double decay_accumulator = 1.0; - - // Examine how well the key frame predicts subsequent frames. - for (i = 0; i < 16; ++i) { - double next_iiratio = (BOOST_FACTOR * local_next_frame.intra_error / - DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error)); - - if (next_iiratio > KF_II_MAX) next_iiratio = KF_II_MAX; - - // Cumulative effect of decay in prediction quality. - if (local_next_frame.pcnt_inter > 0.85) - decay_accumulator *= local_next_frame.pcnt_inter; - else - decay_accumulator *= (0.85 + local_next_frame.pcnt_inter) / 2.0; - - // Keep a running total. - boost_score += (decay_accumulator * next_iiratio); - - // Test various breakout clauses. - if ((local_next_frame.pcnt_inter < 0.05) || (next_iiratio < 1.5) || - (((local_next_frame.pcnt_inter - local_next_frame.pcnt_neutral) < - 0.20) && - (next_iiratio < 3.0)) || - ((boost_score - old_boost_score) < 3.0) || - (local_next_frame.intra_error < 200)) { - break; - } - - old_boost_score = boost_score; - - // Get the next frame details - if (EOF == input_stats(twopass, &local_next_frame)) break; - } - - // If there is tolerable prediction for at least the next 3 frames then - // break out else discard this potential key frame and move on - if (boost_score > 30.0 && (i > 3)) { - is_viable_kf = 1; - } else { - // Reset the file position - reset_fpf_position(twopass, start_pos); - - is_viable_kf = 0; - } - } - - return is_viable_kf; -} - -#define FRAMES_TO_CHECK_DECAY 8 - -static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { - int i, j; - RATE_CONTROL *const rc = &cpi->rc; - TWO_PASS *const twopass = &cpi->twopass; - GF_GROUP *const gf_group = &twopass->gf_group; - const AV1EncoderConfig *const oxcf = &cpi->oxcf; - const FIRSTPASS_STATS first_frame = *this_frame; - const FIRSTPASS_STATS *const start_position = twopass->stats_in; - FIRSTPASS_STATS next_frame; - FIRSTPASS_STATS last_frame; - int kf_bits = 0; - int loop_decay_counter = 0; - double decay_accumulator = 1.0; - double av_decay_accumulator = 0.0; - double zero_motion_accumulator = 1.0; - double boost_score = 0.0; - double kf_mod_err = 0.0; - double kf_group_err = 0.0; - double recent_loop_decay[FRAMES_TO_CHECK_DECAY]; - - av1_zero(next_frame); - - rc->frames_since_key = 0; - - // Reset the GF group data structures. - av1_zero(*gf_group); - - // Is this a forced key frame by interval. - rc->this_key_frame_forced = rc->next_key_frame_forced; - - // Clear the alt ref active flag and last group multi arf flags as they - // can never be set for a key frame. - rc->source_alt_ref_active = 0; - - // KF is always a GF so clear frames till next gf counter. - rc->frames_till_gf_update_due = 0; - - rc->frames_to_key = 1; - - twopass->kf_group_bits = 0; // Total bits available to kf group - twopass->kf_group_error_left = 0; // Group modified error score. - - kf_mod_err = calculate_modified_err(cpi, twopass, oxcf, this_frame); - - // Initialize the decay rates for the recent frames to check - for (j = 0; j < FRAMES_TO_CHECK_DECAY; ++j) recent_loop_decay[j] = 1.0; - - // Find the next keyframe. - i = 0; - while (twopass->stats_in < twopass->stats_in_end && - rc->frames_to_key < cpi->oxcf.key_freq) { - // Accumulate kf group error. - kf_group_err += calculate_modified_err(cpi, twopass, oxcf, this_frame); - - // Load the next frame's stats. - last_frame = *this_frame; - input_stats(twopass, this_frame); - - // Provided that we are not at the end of the file... - if (cpi->oxcf.auto_key && twopass->stats_in < twopass->stats_in_end) { - double loop_decay_rate; - - // Check for a scene cut. - if (test_candidate_kf(twopass, &last_frame, this_frame, - twopass->stats_in)) - break; - - // How fast is the prediction quality decaying? - loop_decay_rate = get_prediction_decay_rate(cpi, twopass->stats_in); - - // We want to know something about the recent past... rather than - // as used elsewhere where we are concerned with decay in prediction - // quality since the last GF or KF. - recent_loop_decay[i % FRAMES_TO_CHECK_DECAY] = loop_decay_rate; - decay_accumulator = 1.0; - for (j = 0; j < FRAMES_TO_CHECK_DECAY; ++j) - decay_accumulator *= recent_loop_decay[j]; - - // Special check for transition or high motion followed by a - // static scene. - if (detect_transition_to_still(cpi, i, cpi->oxcf.key_freq - i, - loop_decay_rate, decay_accumulator)) - break; - - // Step on to the next frame. - ++rc->frames_to_key; - - // If we don't have a real key frame within the next two - // key_freq intervals then break out of the loop. - if (rc->frames_to_key >= 2 * cpi->oxcf.key_freq) break; - } else { - ++rc->frames_to_key; - } - ++i; - } - - // If there is a max kf interval set by the user we must obey it. - // We already breakout of the loop above at 2x max. - // This code centers the extra kf if the actual natural interval - // is between 1x and 2x. - if (cpi->oxcf.auto_key && rc->frames_to_key > cpi->oxcf.key_freq) { - FIRSTPASS_STATS tmp_frame = first_frame; - - rc->frames_to_key /= 2; - - // Reset to the start of the group. - reset_fpf_position(twopass, start_position); - - kf_group_err = 0.0; - - // Rescan to get the correct error data for the forced kf group. - for (i = 0; i < rc->frames_to_key; ++i) { - kf_group_err += calculate_modified_err(cpi, twopass, oxcf, &tmp_frame); - input_stats(twopass, &tmp_frame); - } - rc->next_key_frame_forced = 1; - } else if (twopass->stats_in == twopass->stats_in_end || - rc->frames_to_key >= cpi->oxcf.key_freq) { - rc->next_key_frame_forced = 1; - } else { - rc->next_key_frame_forced = 0; - } - - // Special case for the last key frame of the file. - if (twopass->stats_in >= twopass->stats_in_end) { - // Accumulate kf group error. - kf_group_err += calculate_modified_err(cpi, twopass, oxcf, this_frame); - } - - // Calculate the number of bits that should be assigned to the kf group. - if (twopass->bits_left > 0 && twopass->modified_error_left > 0.0) { - // Maximum number of bits for a single normal frame (not key frame). - const int max_bits = frame_max_bits(rc, &cpi->oxcf); - - // Maximum number of bits allocated to the key frame group. - int64_t max_grp_bits; - - // Default allocation based on bits left and relative - // complexity of the section. - twopass->kf_group_bits = (int64_t)( - twopass->bits_left * (kf_group_err / twopass->modified_error_left)); - - // Clip based on maximum per frame rate defined by the user. - max_grp_bits = (int64_t)max_bits * (int64_t)rc->frames_to_key; - if (twopass->kf_group_bits > max_grp_bits) - twopass->kf_group_bits = max_grp_bits; - } else { - twopass->kf_group_bits = 0; - } - twopass->kf_group_bits = AOMMAX(0, twopass->kf_group_bits); - - // Reset the first pass file position. - reset_fpf_position(twopass, start_position); - - // Scan through the kf group collating various stats used to determine - // how many bits to spend on it. - decay_accumulator = 1.0; - boost_score = 0.0; - const double kf_max_boost = - cpi->oxcf.rc_mode == AOM_Q - ? AOMMIN(AOMMAX(rc->frames_to_key * 2.0, KF_MIN_FRAME_BOOST), - KF_MAX_FRAME_BOOST) - : KF_MAX_FRAME_BOOST; - for (i = 0; i < (rc->frames_to_key - 1); ++i) { - if (EOF == input_stats(twopass, &next_frame)) break; - - // Monitor for static sections. - // For the first frame in kf group, the second ref indicator is invalid. - if (i > 0) { - zero_motion_accumulator = AOMMIN( - zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame)); - } else { - zero_motion_accumulator = next_frame.pcnt_inter - next_frame.pcnt_motion; - } - - // Not all frames in the group are necessarily used in calculating boost. - if ((i <= rc->max_gf_interval) || - ((i <= (rc->max_gf_interval * 4)) && (decay_accumulator > 0.5))) { - const double frame_boost = - calc_frame_boost(cpi, this_frame, 0, kf_max_boost); - - // How fast is prediction quality decaying. - if (!detect_flash(twopass, 0)) { - const double loop_decay_rate = - get_prediction_decay_rate(cpi, &next_frame); - decay_accumulator *= loop_decay_rate; - decay_accumulator = AOMMAX(decay_accumulator, MIN_DECAY_FACTOR); - av_decay_accumulator += decay_accumulator; - ++loop_decay_counter; - } - boost_score += (decay_accumulator * frame_boost); - } - } - if (loop_decay_counter > 0) - av_decay_accumulator /= (double)loop_decay_counter; - - reset_fpf_position(twopass, start_position); - - // Store the zero motion percentage - twopass->kf_zeromotion_pct = (int)(zero_motion_accumulator * 100.0); - - // Calculate a section intra ratio used in setting max loop filter. - twopass->section_intra_rating = calculate_section_intra_ratio( - start_position, twopass->stats_in_end, rc->frames_to_key); - - rc->kf_boost = (int)(av_decay_accumulator * boost_score); - - // Special case for static / slide show content but don't apply - // if the kf group is very short. - if ((zero_motion_accumulator > STATIC_KF_GROUP_FLOAT_THRESH) && - (rc->frames_to_key > 8)) { - rc->kf_boost = AOMMAX(rc->kf_boost, MIN_STATIC_KF_BOOST); - } else { - // Apply various clamps for min and max boost - rc->kf_boost = AOMMAX(rc->kf_boost, (rc->frames_to_key * 3)); - rc->kf_boost = AOMMAX(rc->kf_boost, MIN_KF_BOOST); - } - - // Work out how many bits to allocate for the key frame itself. - kf_bits = calculate_boost_bits((rc->frames_to_key - 1), rc->kf_boost, - twopass->kf_group_bits); - // printf("kf boost = %d kf_bits = %d kf_zeromotion_pct = %d\n", rc->kf_boost, - // kf_bits, twopass->kf_zeromotion_pct); - - // Work out the fraction of the kf group bits reserved for the inter frames - // within the group after discounting the bits for the kf itself. - if (twopass->kf_group_bits) { - twopass->kfgroup_inter_fraction = - (double)(twopass->kf_group_bits - kf_bits) / - (double)twopass->kf_group_bits; - } else { - twopass->kfgroup_inter_fraction = 1.0; - } - - twopass->kf_group_bits -= kf_bits; - - // Save the bits to spend on the key frame. - gf_group->bit_allocation[0] = kf_bits; - gf_group->update_type[0] = KF_UPDATE; - gf_group->rf_level[0] = KF_STD; - - // Note the total error score of the kf group minus the key frame itself. - twopass->kf_group_error_left = (int)(kf_group_err - kf_mod_err); - - // Adjust the count of total modified error left. - // The count of bits left is adjusted elsewhere based on real coded frame - // sizes. - twopass->modified_error_left -= kf_group_err; -} - -static int is_skippable_frame(const AV1_COMP *cpi) { - // If the current frame does not have non-zero motion vector detected in the - // first pass, and so do its previous and forward frames, then this frame - // can be skipped for partition check, and the partition size is assigned - // according to the variance - const TWO_PASS *const twopass = &cpi->twopass; - - return (!frame_is_intra_only(&cpi->common) && - twopass->stats_in - 2 > twopass->stats_in_start && - twopass->stats_in < twopass->stats_in_end && - (twopass->stats_in - 1)->pcnt_inter - - (twopass->stats_in - 1)->pcnt_motion == - 1 && - (twopass->stats_in - 2)->pcnt_inter - - (twopass->stats_in - 2)->pcnt_motion == - 1 && - twopass->stats_in->pcnt_inter - twopass->stats_in->pcnt_motion == 1); -} - -void av1_rc_get_second_pass_params(AV1_COMP *cpi, - EncodeFrameParams *const frame_params) { - AV1_COMMON *const cm = &cpi->common; - CurrentFrame *const current_frame = &cm->current_frame; - RATE_CONTROL *const rc = &cpi->rc; - TWO_PASS *const twopass = &cpi->twopass; - GF_GROUP *const gf_group = &twopass->gf_group; - int frames_left; - FIRSTPASS_STATS this_frame; - - int target_rate; - - frames_left = (int)(twopass->total_stats.count - current_frame->frame_number); - - if (!twopass->stats_in) return; - - // If this is an arf frame then we dont want to read the stats file or - // advance the input pointer as we already have what we need. - if (gf_group->update_type[gf_group->index] == ARF_UPDATE || - gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) { - av1_configure_buffer_updates(cpi, gf_group->update_type[gf_group->index]); - target_rate = gf_group->bit_allocation[gf_group->index]; - target_rate = av1_rc_clamp_pframe_target_size(cpi, target_rate); - rc->base_frame_target = target_rate; - - if (cpi->no_show_kf) { - assert(gf_group->update_type[gf_group->index] == ARF_UPDATE); - frame_params->frame_type = KEY_FRAME; - } else { - frame_params->frame_type = INTER_FRAME; - } - - // Do the firstpass stats indicate that this frame is skippable for the - // partition search? - if (cpi->sf.allow_partition_search_skip && cpi->oxcf.pass == 2) { - cpi->partition_search_skippable_frame = is_skippable_frame(cpi); - } - - return; - } - - aom_clear_system_state(); - - if (cpi->oxcf.rc_mode == AOM_Q) { - twopass->active_worst_quality = cpi->oxcf.cq_level; - } else if (current_frame->frame_number == 0) { - // Special case code for first frame. - const int section_target_bandwidth = - (int)(twopass->bits_left / frames_left); - const double section_length = twopass->total_left_stats.count; - const double section_error = - twopass->total_left_stats.coded_error / section_length; - const double section_intra_skip = - twopass->total_left_stats.intra_skip_pct / section_length; - const double section_inactive_zone = - (twopass->total_left_stats.inactive_zone_rows * 2) / - ((double)cm->mb_rows * section_length); - const int tmp_q = get_twopass_worst_quality( - cpi, section_error, section_intra_skip + section_inactive_zone, - section_target_bandwidth, DEFAULT_GRP_WEIGHT); - - twopass->active_worst_quality = tmp_q; - twopass->baseline_active_worst_quality = tmp_q; - rc->ni_av_qi = tmp_q; - rc->last_q[INTER_FRAME] = tmp_q; - rc->avg_q = av1_convert_qindex_to_q(tmp_q, cm->seq_params.bit_depth); - rc->avg_frame_qindex[INTER_FRAME] = tmp_q; - rc->last_q[KEY_FRAME] = (tmp_q + cpi->oxcf.best_allowed_q) / 2; - rc->avg_frame_qindex[KEY_FRAME] = rc->last_q[KEY_FRAME]; - } - - av1_zero(this_frame); - if (EOF == input_stats(twopass, &this_frame)) return; - - // Set the frame content type flag. - if (this_frame.intra_skip_pct >= FC_ANIMATION_THRESH) - twopass->fr_content_type = FC_GRAPHICS_ANIMATION; - else - twopass->fr_content_type = FC_NORMAL; - - // Keyframe and section processing. - if (rc->frames_to_key == 0 || (cpi->frame_flags & FRAMEFLAGS_KEY)) { - FIRSTPASS_STATS this_frame_copy; - this_frame_copy = this_frame; - frame_params->frame_type = KEY_FRAME; - // Define next KF group and assign bits to it. - find_next_key_frame(cpi, &this_frame); - this_frame = this_frame_copy; - } else { - frame_params->frame_type = INTER_FRAME; - } - - // Define a new GF/ARF group. (Should always enter here for key frames). - if (rc->frames_till_gf_update_due == 0) { - define_gf_group(cpi, &this_frame, frame_params); - - rc->frames_till_gf_update_due = rc->baseline_gf_interval; - -#if ARF_STATS_OUTPUT - { - FILE *fpfile; - fpfile = fopen("arf.stt", "a"); - ++arf_count; - fprintf(fpfile, "%10d %10d %10d %10d %10d\n", current_frame->frame_number, - rc->frames_till_gf_update_due, rc->kf_boost, arf_count, - rc->gfu_boost); - - fclose(fpfile); - } -#endif - } - - av1_configure_buffer_updates(cpi, gf_group->update_type[gf_group->index]); - - // Do the firstpass stats indicate that this frame is skippable for the - // partition search? - if (cpi->sf.allow_partition_search_skip && cpi->oxcf.pass == 2) { - cpi->partition_search_skippable_frame = is_skippable_frame(cpi); - } - - target_rate = gf_group->bit_allocation[gf_group->index]; - - if (frame_params->frame_type == KEY_FRAME) - target_rate = av1_rc_clamp_iframe_target_size(cpi, target_rate); - else - target_rate = av1_rc_clamp_pframe_target_size(cpi, target_rate); - - rc->base_frame_target = target_rate; - - { - const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) - ? cpi->initial_mbs - : cpi->common.MBs; - // The multiplication by 256 reverses a scaling factor of (>> 8) - // applied when combining MB error values for the frame. - twopass->mb_av_energy = log((this_frame.intra_error / num_mbs) + 1.0); - twopass->frame_avg_haar_energy = - log((this_frame.frame_avg_wavelet_energy / num_mbs) + 1.0); - } - - // Update the total stats remaining structure. - subtract_stats(&twopass->total_left_stats, &this_frame); -} - -#define MINQ_ADJ_LIMIT 48 -#define MINQ_ADJ_LIMIT_CQ 20 -#define HIGH_UNDERSHOOT_RATIO 2 -void av1_twopass_postencode_update(AV1_COMP *cpi) { - TWO_PASS *const twopass = &cpi->twopass; - RATE_CONTROL *const rc = &cpi->rc; - const int bits_used = rc->base_frame_target; - - // VBR correction is done through rc->vbr_bits_off_target. Based on the - // sign of this value, a limited % adjustment is made to the target rate - // of subsequent frames, to try and push it back towards 0. This method - // is designed to prevent extreme behaviour at the end of a clip - // or group of frames. - rc->vbr_bits_off_target += rc->base_frame_target - rc->projected_frame_size; - twopass->bits_left = AOMMAX(twopass->bits_left - bits_used, 0); - - // Calculate the pct rc error. - if (rc->total_actual_bits) { - rc->rate_error_estimate = - (int)((rc->vbr_bits_off_target * 100) / rc->total_actual_bits); - rc->rate_error_estimate = clamp(rc->rate_error_estimate, -100, 100); - } else { - rc->rate_error_estimate = 0; - } - - if (cpi->common.current_frame.frame_type != KEY_FRAME) { - twopass->kf_group_bits -= bits_used; - twopass->last_kfgroup_zeromotion_pct = twopass->kf_zeromotion_pct; - } - twopass->kf_group_bits = AOMMAX(twopass->kf_group_bits, 0); - - // If the rate control is drifting consider adjustment to min or maxq. - if ((cpi->oxcf.rc_mode != AOM_Q) && - (cpi->twopass.gf_zeromotion_pct < VLOW_MOTION_THRESHOLD) && - !cpi->rc.is_src_frame_alt_ref) { - const int maxq_adj_limit = - rc->worst_quality - twopass->active_worst_quality; - const int minq_adj_limit = - (cpi->oxcf.rc_mode == AOM_CQ ? MINQ_ADJ_LIMIT_CQ : MINQ_ADJ_LIMIT); - - // Undershoot. - if (rc->rate_error_estimate > cpi->oxcf.under_shoot_pct) { - --twopass->extend_maxq; - if (rc->rolling_target_bits >= rc->rolling_actual_bits) - ++twopass->extend_minq; - // Overshoot. - } else if (rc->rate_error_estimate < -cpi->oxcf.over_shoot_pct) { - --twopass->extend_minq; - if (rc->rolling_target_bits < rc->rolling_actual_bits) - ++twopass->extend_maxq; - } else { - // Adjustment for extreme local overshoot. - if (rc->projected_frame_size > (2 * rc->base_frame_target) && - rc->projected_frame_size > (2 * rc->avg_frame_bandwidth)) - ++twopass->extend_maxq; - - // Unwind undershoot or overshoot adjustment. - if (rc->rolling_target_bits < rc->rolling_actual_bits) - --twopass->extend_minq; - else if (rc->rolling_target_bits > rc->rolling_actual_bits) - --twopass->extend_maxq; - } - - twopass->extend_minq = clamp(twopass->extend_minq, 0, minq_adj_limit); - twopass->extend_maxq = clamp(twopass->extend_maxq, 0, maxq_adj_limit); - - // If there is a big and undexpected undershoot then feed the extra - // bits back in quickly. One situation where this may happen is if a - // frame is unexpectedly almost perfectly predicted by the ARF or GF - // but not very well predcited by the previous frame. - if (!frame_is_kf_gf_arf(cpi) && !cpi->rc.is_src_frame_alt_ref) { - int fast_extra_thresh = rc->base_frame_target / HIGH_UNDERSHOOT_RATIO; - if (rc->projected_frame_size < fast_extra_thresh) { - rc->vbr_bits_off_target_fast += - fast_extra_thresh - rc->projected_frame_size; - rc->vbr_bits_off_target_fast = - AOMMIN(rc->vbr_bits_off_target_fast, (4 * rc->avg_frame_bandwidth)); - - // Fast adaptation of minQ if necessary to use up the extra bits. - if (rc->avg_frame_bandwidth) { - twopass->extend_minq_fast = - (int)(rc->vbr_bits_off_target_fast * 8 / rc->avg_frame_bandwidth); - } - twopass->extend_minq_fast = AOMMIN( - twopass->extend_minq_fast, minq_adj_limit - twopass->extend_minq); - } else if (rc->vbr_bits_off_target_fast) { - twopass->extend_minq_fast = AOMMIN( - twopass->extend_minq_fast, minq_adj_limit - twopass->extend_minq); - } else { - twopass->extend_minq_fast = 0; - } - } - } -} diff --git a/third_party/aom/av1/encoder/firstpass.h b/third_party/aom/av1/encoder/firstpass.h index be1101a4b0..1b8636c66f 100644 --- a/third_party/aom/av1/encoder/firstpass.h +++ b/third_party/aom/av1/encoder/firstpass.h @@ -21,35 +21,7 @@ extern "C" { #endif -#if CONFIG_FP_MB_STATS - -#define FPMB_DCINTRA_MASK 0x01 - -#define FPMB_MOTION_ZERO_MASK 0x02 -#define FPMB_MOTION_LEFT_MASK 0x04 -#define FPMB_MOTION_RIGHT_MASK 0x08 -#define FPMB_MOTION_UP_MASK 0x10 -#define FPMB_MOTION_DOWN_MASK 0x20 - -#define FPMB_ERROR_SMALL_MASK 0x40 -#define FPMB_ERROR_LARGE_MASK 0x80 -#define FPMB_ERROR_SMALL_TH 2000 -#define FPMB_ERROR_LARGE_TH 48000 - -typedef struct { - uint8_t *mb_stats_start; - uint8_t *mb_stats_end; -} FIRSTPASS_MB_STATS; -#endif - -// Length of the bi-predictive frame group (BFG) -// NOTE: Currently each BFG contains one backward ref (BWF) frame plus a certain -// number of bi-predictive frames. -#define BFG_INTERVAL 2 -// The maximum number of extra ALTREF's except ALTREF_FRAME -#define MAX_EXT_ARFS (REF_FRAMES - BWDREF_FRAME - 1) - -#define MIN_EXT_ARF_INTERVAL 4 +#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x)-0.000001 : (x) + 0.000001) #define MIN_ZERO_MOTION 0.95 #define MAX_SR_CODED_ERROR 40 @@ -59,45 +31,79 @@ typedef struct { #define VLOW_MOTION_THRESHOLD 950 typedef struct { + // Frame number in display order, if stats are for a single frame. + // No real meaning for a collection of frames. double frame; + // Weight assigned to this frame (or total weight for the collection of + // frames) currently based on intra factor and brightness factor. This is used + // to distribute bits betweeen easier and harder frames. double weight; + // Intra prediction error. double intra_error; + // Average wavelet energy computed using Discrete Wavelet Transform (DWT). double frame_avg_wavelet_energy; + // Best of intra pred error and inter pred error using last frame as ref. double coded_error; + // Best of intra pred error and inter pred error using golden frame as ref. double sr_coded_error; + // Percentage of blocks with inter pred error < intra pred error. double pcnt_inter; + // Percentage of blocks using (inter prediction and) non-zero motion vectors. double pcnt_motion; + // Percentage of blocks where golden frame was the best reference. That is: + // inter pred error using golden frame < inter pred error using last frame and + // inter pred error using golden frame < intra pred error double pcnt_second_ref; + // Percentage of blocks where intra and inter prediction errors were very + // close. Note that this is a 'weighted count', that is, the so blocks may be + // weighted by how close the two errors were. double pcnt_neutral; + // Percentage of blocks that have almost no intra error residual + // (i.e. are in effect completely flat and untextured in the intra + // domain). In natural videos this is uncommon, but it is much more + // common in animations, graphics and screen content, so may be used + // as a signal to detect these types of content. double intra_skip_pct; - double inactive_zone_rows; // Image mask rows top and bottom. - double inactive_zone_cols; // Image mask columns at left and right edges. + // Image mask rows top and bottom. + double inactive_zone_rows; + // Image mask columns at left and right edges. + double inactive_zone_cols; + // Average of row motion vectors. double MVr; + // Mean of absolute value of row motion vectors. double mvr_abs; + // Mean of column motion vectors. double MVc; + // Mean of absolute value of column motion vectors. double mvc_abs; + // Variance of row motion vectors. double MVrv; + // Variance of column motion vectors. double MVcv; + // Value in range [-1,1] indicating fraction of row and column motion vectors + // that point inwards (negative MV value) or outwards (positive MV value). + // For example, value of 1 indicates, all row/column MVs are inwards. double mv_in_out_count; + // Count of unique non-zero motion vectors. double new_mv_count; + // Duration of the frame / collection of frames. double duration; + // 1.0 if stats are for a single frame, OR + // Number of frames in this collection for which the stats are accumulated. double count; // standard deviation for (0, 0) motion prediction error double raw_error_stdev; } FIRSTPASS_STATS; enum { - KF_UPDATE = 0, - LF_UPDATE = 1, - GF_UPDATE = 2, - ARF_UPDATE = 3, - OVERLAY_UPDATE = 4, - BRF_UPDATE = 5, // Backward Reference Frame - LAST_BIPRED_UPDATE = 6, // Last Bi-predictive Frame - BIPRED_UPDATE = 7, // Bi-predictive Frame, but not the last one - INTNL_OVERLAY_UPDATE = 8, // Internal Overlay Frame - INTNL_ARF_UPDATE = 9, // Internal Altref Frame (candidate for ALTREF2) - FRAME_UPDATE_TYPES = 10 + KF_UPDATE, + LF_UPDATE, + GF_UPDATE, + ARF_UPDATE, + OVERLAY_UPDATE, + INTNL_OVERLAY_UPDATE, // Internal Overlay Frame + INTNL_ARF_UPDATE, // Internal Altref Frame + FRAME_UPDATE_TYPES } UENUM1BYTE(FRAME_UPDATE_TYPE); #define FC_ANIMATION_THRESH 0.15 @@ -109,18 +115,15 @@ enum { typedef struct { unsigned char index; - RATE_FACTOR_LEVEL rf_level[MAX_STATIC_GF_GROUP_LENGTH + 1]; FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH + 1]; unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1]; unsigned char arf_update_idx[MAX_STATIC_GF_GROUP_LENGTH + 1]; - unsigned char arf_ref_idx[MAX_STATIC_GF_GROUP_LENGTH + 1]; unsigned char arf_pos_in_gf[MAX_STATIC_GF_GROUP_LENGTH + 1]; unsigned char pyramid_level[MAX_STATIC_GF_GROUP_LENGTH + 1]; unsigned char pyramid_height; unsigned char pyramid_lvl_nodes[MAX_PYRAMID_LVL]; - unsigned char brf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1]; - unsigned char bidir_pred_enabled[MAX_STATIC_GF_GROUP_LENGTH + 1]; int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 1]; + int size; } GF_GROUP; typedef struct { @@ -139,11 +142,6 @@ typedef struct { double mb_av_energy; double frame_avg_haar_energy; -#if CONFIG_FP_MB_STATS - uint8_t *frame_mb_stats_buf; - uint8_t *this_frame_mb_stats; - FIRSTPASS_MB_STATS firstpass_mb_stats; -#endif // An indication of the content type of the current frame FRAME_CONTENT_TYPE fr_content_type; @@ -160,7 +158,6 @@ typedef struct { int kf_zeromotion_pct; int last_kfgroup_zeromotion_pct; - int gf_zeromotion_pct; int active_worst_quality; int baseline_active_worst_quality; int extend_minq; @@ -172,37 +169,14 @@ typedef struct { struct AV1_COMP; struct EncodeFrameParams; +struct AV1EncoderConfig; void av1_init_first_pass(struct AV1_COMP *cpi); void av1_rc_get_first_pass_params(struct AV1_COMP *cpi); void av1_first_pass(struct AV1_COMP *cpi, const int64_t ts_duration); void av1_end_first_pass(struct AV1_COMP *cpi); -void av1_init_second_pass(struct AV1_COMP *cpi); -void av1_rc_get_second_pass_params( - struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params); - -// Post encode update of the rate control parameters for 2-pass -void av1_twopass_postencode_update(struct AV1_COMP *cpi); - -static INLINE int get_number_of_extra_arfs(int interval, int arf_pending, - int max_pyr_height) { - // Max extra (internal) alt-refs allowed based on interval. - int extra_arfs_from_interval = 0; - if (arf_pending && MAX_EXT_ARFS > 0) { - extra_arfs_from_interval = - (interval >= MIN_EXT_ARF_INTERVAL * (MAX_EXT_ARFS + 1)) - ? MAX_EXT_ARFS - : (interval >= MIN_EXT_ARF_INTERVAL * MAX_EXT_ARFS) - ? MAX_EXT_ARFS - 1 - : 0; - } - // Max extra (internal) alt-refs allowed based on max pyramid height. - assert(max_pyr_height >= 1); - const int ext_arfs_from_max_height = max_pyr_height - 1; - // Finally, min of the two above is our actual max allowance. - return AOMMIN(extra_arfs_from_interval, ext_arfs_from_max_height); -} +void av1_twopass_zero_stats(FIRSTPASS_STATS *section); #ifdef __cplusplus } // extern "C" diff --git a/third_party/aom/av1/encoder/global_motion.c b/third_party/aom/av1/encoder/global_motion.c index 142e44d804..b8b13c3e8f 100644 --- a/third_party/aom/av1/encoder/global_motion.c +++ b/third_party/aom/av1/encoder/global_motion.c @@ -32,7 +32,6 @@ #define MIN_INLIER_PROB 0.1 #define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR) -#define USE_GM_FEATURE_BASED 1 // Border over which to compute the global motion #define ERRORADV_BORDER 0 @@ -276,7 +275,6 @@ static unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm, return buf_8bit; } -#if USE_GM_FEATURE_BASED static int compute_global_motion_feature_based( TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref, int bit_depth, int *num_inliers_by_motion, double *params_by_motion, @@ -331,7 +329,7 @@ static int compute_global_motion_feature_based( } return 0; } -#else + static INLINE RansacFuncDouble get_ransac_double_prec_type(TransformationType type) { switch (type) { @@ -543,6 +541,7 @@ static INLINE void solve_2x2_system(const double *M, const double *b, output_vec[1] = -M[2] * mult_b0 + M_0 * mult_b1; } +/* static INLINE void image_difference(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int16_t *dst, int dst_stride, int height, @@ -557,6 +556,7 @@ static INLINE void image_difference(const uint8_t *src, int src_stride, } } } +*/ // Compute an image gradient using a sobel filter. // If dir == 1, compute the x gradient. If dir == 0, compute y. This function @@ -869,19 +869,22 @@ static int compute_global_motion_disflow_based( } return 0; } -#endif int av1_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref, int bit_depth, + GlobalMotionEstimationType gm_estimation_type, int *num_inliers_by_motion, double *params_by_motion, int num_motions) { -#if USE_GM_FEATURE_BASED - return compute_global_motion_feature_based(type, frm, ref, bit_depth, - num_inliers_by_motion, - params_by_motion, num_motions); -#else - return compute_global_motion_disflow_based(type, frm, ref, bit_depth, - num_inliers_by_motion, - params_by_motion, num_motions); -#endif + switch (gm_estimation_type) { + case GLOBAL_MOTION_FEATURE_BASED: + return compute_global_motion_feature_based(type, frm, ref, bit_depth, + num_inliers_by_motion, + params_by_motion, num_motions); + case GLOBAL_MOTION_DISFLOW_BASED: + return compute_global_motion_disflow_based(type, frm, ref, bit_depth, + num_inliers_by_motion, + params_by_motion, num_motions); + default: assert(0 && "Unknown global motion estimation type"); + } + return 0; } diff --git a/third_party/aom/av1/encoder/global_motion.h b/third_party/aom/av1/encoder/global_motion.h index 42cf221697..2cfddad752 100644 --- a/third_party/aom/av1/encoder/global_motion.h +++ b/third_party/aom/av1/encoder/global_motion.h @@ -22,6 +22,11 @@ extern "C" { #define RANSAC_NUM_MOTIONS 1 +typedef enum { + GLOBAL_MOTION_FEATURE_BASED, + GLOBAL_MOTION_DISFLOW_BASED, +} GlobalMotionEstimationType; + void av1_convert_model_to_params(const double *params, WarpedMotionParams *model); @@ -56,6 +61,7 @@ int64_t av1_refine_integerized_param(WarpedMotionParams *wm, */ int av1_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref, int bit_depth, + GlobalMotionEstimationType gm_estimation_type, int *num_inliers_by_motion, double *params_by_motion, int num_motions); #ifdef __cplusplus diff --git a/third_party/aom/av1/encoder/gop_structure.c b/third_party/aom/av1/encoder/gop_structure.c new file mode 100644 index 0000000000..73cb0ed421 --- /dev/null +++ b/third_party/aom/av1/encoder/gop_structure.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2019, 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 + +#include "config/aom_config.h" +#include "config/aom_scale_rtcd.h" + +#include "aom/aom_codec.h" +#include "aom/aom_encoder.h" + +#include "aom_ports/system_state.h" + +#include "av1/common/onyxc_int.h" + +#include "av1/encoder/encoder.h" +#include "av1/encoder/firstpass.h" +#include "av1/encoder/gop_structure.h" + +// Set parameters for frames between 'start' and 'end' (excluding both). +static void set_multi_layer_params(GF_GROUP *const gf_group, int start, int end, + int *frame_ind, int arf_ind, int level) { + assert(level >= MIN_PYRAMID_LVL); + const int num_frames_to_process = end - start - 1; + assert(num_frames_to_process >= 0); + if (num_frames_to_process == 0) return; + + // Either we are at the last level of the pyramid, or we don't have enough + // frames between 'l' and 'r' to create one more level. + if (level == MIN_PYRAMID_LVL || num_frames_to_process < 3) { + // Leaf nodes. + while (++start < end) { + gf_group->update_type[*frame_ind] = LF_UPDATE; + gf_group->arf_src_offset[*frame_ind] = 0; + gf_group->arf_pos_in_gf[*frame_ind] = 0; + gf_group->arf_update_idx[*frame_ind] = arf_ind; + gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL; + ++gf_group->pyramid_lvl_nodes[MIN_PYRAMID_LVL]; + ++(*frame_ind); + } + } else { + const int m = (start + end) / 2; + const int arf_pos_in_gf = *frame_ind; + + // Internal ARF. + gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE; + gf_group->arf_src_offset[*frame_ind] = m - start - 1; + gf_group->arf_pos_in_gf[*frame_ind] = 0; + gf_group->arf_update_idx[*frame_ind] = 1; // mark all internal ARF 1 + gf_group->pyramid_level[*frame_ind] = level; + ++gf_group->pyramid_lvl_nodes[level]; + ++(*frame_ind); + + // Frames displayed before this internal ARF. + set_multi_layer_params(gf_group, start, m, frame_ind, 1, level - 1); + + // Overlay for internal ARF. + gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE; + gf_group->arf_src_offset[*frame_ind] = 0; + gf_group->arf_pos_in_gf[*frame_ind] = arf_pos_in_gf; // For bit allocation. + gf_group->arf_update_idx[*frame_ind] = 1; + gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL; + ++(*frame_ind); + + // Frames displayed after this internal ARF. + set_multi_layer_params(gf_group, m, end, frame_ind, arf_ind, level - 1); + } +} + +static int construct_multi_layer_gf_structure( + GF_GROUP *const gf_group, int gf_interval, int pyr_height, + FRAME_UPDATE_TYPE first_frame_update_type) { + gf_group->pyramid_height = pyr_height; + av1_zero_array(gf_group->pyramid_lvl_nodes, MAX_PYRAMID_LVL); + int frame_index = 0; + + // Keyframe / Overlay frame / Golden frame. + assert(gf_interval >= 1); + assert(first_frame_update_type == KF_UPDATE || + first_frame_update_type == OVERLAY_UPDATE || + first_frame_update_type == GF_UPDATE); + gf_group->update_type[frame_index] = first_frame_update_type; + gf_group->arf_src_offset[frame_index] = 0; + gf_group->arf_pos_in_gf[frame_index] = 0; + gf_group->arf_update_idx[frame_index] = 0; + gf_group->pyramid_level[frame_index] = MIN_PYRAMID_LVL; + ++frame_index; + + // ALTREF. + const int use_altref = (gf_group->pyramid_height > 0); + if (use_altref) { + gf_group->update_type[frame_index] = ARF_UPDATE; + gf_group->arf_src_offset[frame_index] = gf_interval - 1; + gf_group->arf_pos_in_gf[frame_index] = 0; + gf_group->arf_update_idx[frame_index] = 0; + gf_group->pyramid_level[frame_index] = gf_group->pyramid_height; + ++frame_index; + } + + // Rest of the frames. + const int next_height = + use_altref ? gf_group->pyramid_height - 1 : gf_group->pyramid_height; + assert(next_height >= MIN_PYRAMID_LVL); + set_multi_layer_params(gf_group, 0, gf_interval, &frame_index, 0, + next_height); + return frame_index; +} + +#define CHECK_GF_PARAMETER 0 +#if CHECK_GF_PARAMETER +void check_frame_params(GF_GROUP *const gf_group, int gf_interval) { + static const char *update_type_strings[FRAME_UPDATE_TYPES] = { + "KF_UPDATE", "LF_UPDATE", "GF_UPDATE", + "ARF_UPDATE", "OVERLAY_UPDATE", "INTNL_OVERLAY_UPDATE", + "INTNL_ARF_UPDATE" + }; + FILE *fid = fopen("GF_PARAMS.txt", "a"); + + fprintf(fid, "\ngf_interval = {%d}\n", gf_interval); + for (int i = 0; i <= gf_group->size; ++i) { + fprintf(fid, "#%2d : %s %d %d %d %d\n", i, + update_type_strings[gf_group->update_type[i]], + gf_group->arf_src_offset[i], gf_group->arf_pos_in_gf[i], + gf_group->arf_update_idx[i], gf_group->pyramid_level[i]); + } + + fprintf(fid, "number of nodes in each level: \n"); + for (int i = 0; i < gf_group->pyramid_height; ++i) { + fprintf(fid, "lvl %d: %d ", i, gf_group->pyramid_lvl_nodes[i]); + } + fprintf(fid, "\n"); + fclose(fid); +} +#endif // CHECK_GF_PARAMETER + +static INLINE int max_pyramid_height_from_width(int pyramid_width) { + if (pyramid_width > 12) return 4; + if (pyramid_width > 6) return 3; + if (pyramid_width > 3) return 2; + if (pyramid_width > 1) return 1; + return 0; +} + +static int get_pyramid_height(const AV1_COMP *const cpi) { + const RATE_CONTROL *const rc = &cpi->rc; + assert(IMPLIES(cpi->oxcf.gf_max_pyr_height == MIN_PYRAMID_LVL, + !rc->source_alt_ref_pending)); // define_gf_group() enforced. + if (!rc->source_alt_ref_pending) { + return MIN_PYRAMID_LVL; + } + assert(cpi->oxcf.gf_max_pyr_height > MIN_PYRAMID_LVL); + if (!cpi->internal_altref_allowed) { + assert(MIN_PYRAMID_LVL + 1 <= cpi->oxcf.gf_max_pyr_height); + return MIN_PYRAMID_LVL + 1; + } + return AOMMIN(max_pyramid_height_from_width(rc->baseline_gf_interval), + cpi->oxcf.gf_max_pyr_height); +} + +void av1_gop_setup_structure(AV1_COMP *cpi, + const EncodeFrameParams *const frame_params) { + RATE_CONTROL *const rc = &cpi->rc; + TWO_PASS *const twopass = &cpi->twopass; + GF_GROUP *const gf_group = &twopass->gf_group; + const int key_frame = (frame_params->frame_type == KEY_FRAME); + const FRAME_UPDATE_TYPE first_frame_update_type = + key_frame ? KF_UPDATE + : rc->source_alt_ref_active ? OVERLAY_UPDATE : GF_UPDATE; + gf_group->size = construct_multi_layer_gf_structure( + gf_group, rc->baseline_gf_interval, get_pyramid_height(cpi), + first_frame_update_type); + + // We need to configure the frame at the end of the sequence + 1 that + // will be the start frame for the next group. Otherwise prior to the + // call to av1_get_second_pass_params(), the data will be undefined. + gf_group->update_type[gf_group->size] = + (rc->source_alt_ref_pending) ? OVERLAY_UPDATE : GF_UPDATE; + gf_group->arf_update_idx[gf_group->size] = 0; + gf_group->arf_pos_in_gf[gf_group->size] = 0; + +#if CHECK_GF_PARAMETER + check_frame_params(gf_group, rc->baseline_gf_interval); +#endif +} diff --git a/third_party/aom/av1/encoder/gop_structure.h b/third_party/aom/av1/encoder/gop_structure.h new file mode 100644 index 0000000000..d9d5ae731d --- /dev/null +++ b/third_party/aom/av1/encoder/gop_structure.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, 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. + */ + +#ifndef AOM_AV1_ENCODER_GOP_STRUCTURE_H_ +#define AOM_AV1_ENCODER_GOP_STRUCTURE_H_ + +#include "av1/common/onyxc_int.h" +#include "av1/encoder/ratectrl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct AV1_COMP; +struct EncodeFrameParams; + +// Set up the Group-Of-Pictures structure for this GF_GROUP. This involves +// deciding where to place the various FRAME_UPDATE_TYPEs in the group. It does +// this primarily by setting the contents of +// cpi->twopass.gf_group.update_type[]. +void av1_gop_setup_structure( + struct AV1_COMP *cpi, const struct EncodeFrameParams *const frame_params); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_GOP_STRUCTURE_H_ diff --git a/third_party/aom/av1/encoder/hash_motion.c b/third_party/aom/av1/encoder/hash_motion.c index 4c872f15aa..00915e5278 100644 --- a/third_party/aom/av1/encoder/hash_motion.c +++ b/third_party/aom/av1/encoder/hash_motion.c @@ -393,8 +393,9 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, uint32_t *hash_value1, uint32_t *hash_value2, int use_highbitdepth, MACROBLOCK *x) { uint32_t to_hash[4]; - const int add_value = hash_block_size_to_index(block_size) << crc_bits; + int add_value = hash_block_size_to_index(block_size); assert(add_value >= 0); + add_value <<= crc_bits; const int crc_mask = (1 << crc_bits) - 1; // 2x2 subblock hash values in current CU diff --git a/third_party/aom/av1/encoder/level.c b/third_party/aom/av1/encoder/level.c new file mode 100644 index 0000000000..5e49ec0e89 --- /dev/null +++ b/third_party/aom/av1/encoder/level.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2019, 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 "aom_ports/system_state.h" + +#include "av1/encoder/encoder.h" +#include "av1/encoder/level.h" + +#define UNDEFINED_LEVEL \ + { \ + .level = SEQ_LEVEL_MAX, .max_picture_size = 0, .max_h_size = 0, \ + .max_v_size = 0, .max_display_rate = 0, .max_decode_rate = 0, \ + .max_header_rate = 0, .main_mbps = 0, .high_mbps = 0, .main_cr = 0, \ + .high_cr = 0, .max_tiles = 0, .max_tile_cols = 0 \ + } + +static const AV1LevelSpec av1_level_defs[SEQ_LEVELS] = { + { .level = SEQ_LEVEL_2_0, + .max_picture_size = 147456, + .max_h_size = 2048, + .max_v_size = 1152, + .max_display_rate = 4423680L, + .max_decode_rate = 5529600L, + .max_header_rate = 150, + .main_mbps = 1.5, + .high_mbps = 0, + .main_cr = 2.0, + .high_cr = 0, + .max_tiles = 8, + .max_tile_cols = 4 }, + { .level = SEQ_LEVEL_2_1, + .max_picture_size = 278784, + .max_h_size = 2816, + .max_v_size = 1584, + .max_display_rate = 8363520L, + .max_decode_rate = 10454400L, + .max_header_rate = 150, + .main_mbps = 3.0, + .high_mbps = 0, + .main_cr = 2.0, + .high_cr = 0, + .max_tiles = 8, + .max_tile_cols = 4 }, + UNDEFINED_LEVEL, + UNDEFINED_LEVEL, + { .level = SEQ_LEVEL_3_0, + .max_picture_size = 665856, + .max_h_size = 4352, + .max_v_size = 2448, + .max_display_rate = 19975680L, + .max_decode_rate = 24969600L, + .max_header_rate = 150, + .main_mbps = 6.0, + .high_mbps = 0, + .main_cr = 2.0, + .high_cr = 0, + .max_tiles = 16, + .max_tile_cols = 6 }, + { .level = SEQ_LEVEL_3_1, + .max_picture_size = 1065024, + .max_h_size = 5504, + .max_v_size = 3096, + .max_display_rate = 31950720L, + .max_decode_rate = 39938400L, + .max_header_rate = 150, + .main_mbps = 10.0, + .high_mbps = 0, + .main_cr = 2.0, + .high_cr = 0, + .max_tiles = 16, + .max_tile_cols = 6 }, + UNDEFINED_LEVEL, + UNDEFINED_LEVEL, + { .level = SEQ_LEVEL_4_0, + .max_picture_size = 2359296, + .max_h_size = 6144, + .max_v_size = 3456, + .max_display_rate = 70778880L, + .max_decode_rate = 77856768L, + .max_header_rate = 300, + .main_mbps = 12.0, + .high_mbps = 30.0, + .main_cr = 4.0, + .high_cr = 4.0, + .max_tiles = 32, + .max_tile_cols = 8 }, + { .level = SEQ_LEVEL_4_1, + .max_picture_size = 2359296, + .max_h_size = 6144, + .max_v_size = 3456, + .max_display_rate = 141557760L, + .max_decode_rate = 155713536L, + .max_header_rate = 300, + .main_mbps = 20.0, + .high_mbps = 50.0, + .main_cr = 4.0, + .high_cr = 4.0, + .max_tiles = 32, + .max_tile_cols = 8 }, + UNDEFINED_LEVEL, + UNDEFINED_LEVEL, + { .level = SEQ_LEVEL_5_0, + .max_picture_size = 8912896, + .max_h_size = 8192, + .max_v_size = 4352, + .max_display_rate = 267386880L, + .max_decode_rate = 273715200L, + .max_header_rate = 300, + .main_mbps = 30.0, + .high_mbps = 100.0, + .main_cr = 6.0, + .high_cr = 4.0, + .max_tiles = 64, + .max_tile_cols = 8 }, + { .level = SEQ_LEVEL_5_1, + .max_picture_size = 8912896, + .max_h_size = 8192, + .max_v_size = 4352, + .max_display_rate = 534773760L, + .max_decode_rate = 547430400L, + .max_header_rate = 300, + .main_mbps = 40.0, + .high_mbps = 160.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 64, + .max_tile_cols = 8 }, + { .level = SEQ_LEVEL_5_2, + .max_picture_size = 8912896, + .max_h_size = 8192, + .max_v_size = 4352, + .max_display_rate = 1069547520L, + .max_decode_rate = 1094860800L, + .max_header_rate = 300, + .main_mbps = 60.0, + .high_mbps = 240.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 64, + .max_tile_cols = 8 }, + { .level = SEQ_LEVEL_5_3, + .max_picture_size = 8912896, + .max_h_size = 8192, + .max_v_size = 4352, + .max_display_rate = 1069547520L, + .max_decode_rate = 1176502272L, + .max_header_rate = 300, + .main_mbps = 60.0, + .high_mbps = 240.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 64, + .max_tile_cols = 8 }, + { .level = SEQ_LEVEL_6_0, + .max_picture_size = 35651584, + .max_h_size = 16384, + .max_v_size = 8704, + .max_display_rate = 1069547520L, + .max_decode_rate = 1176502272L, + .max_header_rate = 300, + .main_mbps = 60.0, + .high_mbps = 240.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 128, + .max_tile_cols = 16 }, + { .level = SEQ_LEVEL_6_1, + .max_picture_size = 35651584, + .max_h_size = 16384, + .max_v_size = 8704, + .max_display_rate = 2139095040L, + .max_decode_rate = 2189721600L, + .max_header_rate = 300, + .main_mbps = 100.0, + .high_mbps = 480.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 128, + .max_tile_cols = 16 }, + { .level = SEQ_LEVEL_6_2, + .max_picture_size = 35651584, + .max_h_size = 16384, + .max_v_size = 8704, + .max_display_rate = 4278190080L, + .max_decode_rate = 4379443200L, + .max_header_rate = 300, + .main_mbps = 160.0, + .high_mbps = 800.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 128, + .max_tile_cols = 16 }, + { .level = SEQ_LEVEL_6_3, + .max_picture_size = 35651584, + .max_h_size = 16384, + .max_v_size = 8704, + .max_display_rate = 4278190080L, + .max_decode_rate = 4706009088L, + .max_header_rate = 300, + .main_mbps = 160.0, + .high_mbps = 800.0, + .main_cr = 8.0, + .high_cr = 4.0, + .max_tiles = 128, + .max_tile_cols = 16 }, + UNDEFINED_LEVEL, + UNDEFINED_LEVEL, + UNDEFINED_LEVEL, + UNDEFINED_LEVEL, +}; + +typedef enum { + LUMA_PIC_SIZE_TOO_LARGE, + LUMA_PIC_H_SIZE_TOO_LARGE, + LUMA_PIC_V_SIZE_TOO_LARGE, + TOO_MANY_TILE_COLUMNS, + TOO_MANY_TILES, + TILE_TOO_LARGE, + CROPPED_TILE_WIDTH_TOO_SMALL, + CROPPED_TILE_HEIGHT_TOO_SMALL, + TILE_WIDTH_INVALID, + FRAME_HEADER_RATE_TOO_HIGH, + DISPLAY_RATE_TOO_HIGH, + DECODE_RATE_TOO_HIGH, + CR_TOO_SMALL, + + TARGET_LEVEL_FAIL_IDS, + TARGET_LEVEL_OK, +} TARGET_LEVEL_FAIL_ID; + +static const char *level_fail_messages[TARGET_LEVEL_FAIL_IDS] = { + "The picture size is too large.", + "The picture width is too large.", + "The picture height is too large.", + "Too many tile columns are used.", + "Too many tiles are used.", + "The tile size is too large.", + "The cropped tile width is less than 8", + "The cropped tile height is less than 8", + "The tile width is invalid", + "The frame header rate is too high", + "The display luma sample rate is too high", + "The decoded luma sample rate is too high", + "The compression ratio is too small", +}; + +static double get_min_cr(const AV1LevelSpec *const level_spec, int tier, + int is_still_picture, int64_t decoded_sample_rate) { + if (is_still_picture) return 0.8; + const double min_cr_basis = tier ? level_spec->high_cr : level_spec->main_cr; + const double speed_adj = + (double)decoded_sample_rate / level_spec->max_display_rate; + return AOMMAX(min_cr_basis * speed_adj, 0.8); +} + +static TARGET_LEVEL_FAIL_ID check_level_constraints( + const AV1LevelSpec *const target_level_spec, + const AV1LevelSpec *const level_spec, + const AV1LevelStats *const level_stats, int tier, int is_still_picture) { + const double min_cr = get_min_cr(target_level_spec, tier, is_still_picture, + level_spec->max_decode_rate); + TARGET_LEVEL_FAIL_ID fail_id = TARGET_LEVEL_OK; + + do { + if (level_spec->max_picture_size > target_level_spec->max_picture_size) { + fail_id = LUMA_PIC_SIZE_TOO_LARGE; + break; + } + + if (level_spec->max_h_size > target_level_spec->max_h_size) { + fail_id = LUMA_PIC_H_SIZE_TOO_LARGE; + break; + } + + if (level_spec->max_v_size > target_level_spec->max_v_size) { + fail_id = LUMA_PIC_V_SIZE_TOO_LARGE; + break; + } + + if (level_spec->max_tile_cols > target_level_spec->max_tile_cols) { + fail_id = TOO_MANY_TILE_COLUMNS; + break; + } + + if (level_spec->max_tiles > target_level_spec->max_tiles) { + fail_id = TOO_MANY_TILES; + break; + } + + if (level_spec->max_header_rate > target_level_spec->max_header_rate) { + fail_id = FRAME_HEADER_RATE_TOO_HIGH; + break; + } + + if (level_spec->max_display_rate > target_level_spec->max_display_rate) { + fail_id = DISPLAY_RATE_TOO_HIGH; + break; + } + + if (level_spec->max_decode_rate > target_level_spec->max_decode_rate) { + fail_id = DECODE_RATE_TOO_HIGH; + break; + } + + if (level_stats->max_tile_size > 4096 * 2304) { + fail_id = TILE_TOO_LARGE; + break; + } + + if (level_stats->min_cropped_tile_width < 8) { + fail_id = CROPPED_TILE_WIDTH_TOO_SMALL; + break; + } + + if (level_stats->min_cropped_tile_height < 8) { + fail_id = CROPPED_TILE_HEIGHT_TOO_SMALL; + break; + } + + if (!level_stats->tile_width_is_valid) { + fail_id = TILE_WIDTH_INVALID; + break; + } + + if (level_stats->min_cr < min_cr) { + fail_id = CR_TOO_SMALL; + break; + } + } while (0); + + return fail_id; +} + +static INLINE int is_in_operating_point(int operating_point, + int temporal_layer_id, + int spatial_layer_id) { + if (!operating_point) return 1; + + return ((operating_point >> temporal_layer_id) & 1) && + ((operating_point >> (spatial_layer_id + 8)) & 1); +} + +static void get_tile_stats(const AV1_COMP *const cpi, int *max_tile_size, + int *min_cropped_tile_width, + int *min_cropped_tile_height, + int *tile_width_valid) { + const AV1_COMMON *const cm = &cpi->common; + const int tile_cols = cm->tile_cols; + const int tile_rows = cm->tile_rows; + + *max_tile_size = 0; + *min_cropped_tile_width = INT_MAX; + *min_cropped_tile_height = INT_MAX; + *tile_width_valid = 1; + + for (int tile_row = 0; tile_row < tile_rows; ++tile_row) { + for (int tile_col = 0; tile_col < tile_cols; ++tile_col) { + const TileInfo *const tile_info = + &cpi->tile_data[tile_row * cm->tile_cols + tile_col].tile_info; + const int tile_width = + (tile_info->mi_col_end - tile_info->mi_col_start) * MI_SIZE; + const int tile_height = + (tile_info->mi_row_end - tile_info->mi_row_start) * MI_SIZE; + const int tile_size = tile_width * tile_height; + *max_tile_size = AOMMAX(*max_tile_size, tile_size); + + const int cropped_tile_width = + cm->width - tile_info->mi_col_start * MI_SIZE; + const int cropped_tile_height = + cm->height - tile_info->mi_row_start * MI_SIZE; + *min_cropped_tile_width = + AOMMIN(*min_cropped_tile_width, cropped_tile_width); + *min_cropped_tile_height = + AOMMIN(*min_cropped_tile_height, cropped_tile_height); + + const int is_right_most_tile = tile_info->mi_col_end == cm->mi_cols; + if (!is_right_most_tile) { + if (av1_superres_scaled(cm)) + *tile_width_valid &= tile_width >= 128; + else + *tile_width_valid &= tile_width >= 64; + } + } + } +} + +static int store_frame_record(int64_t ts_start, int64_t ts_end, int pic_size, + int frame_header_count, int show_frame, + int show_existing_frame, + FrameWindowBuffer *const buffer) { + if (buffer->num < FRAME_WINDOW_SIZE) { + ++buffer->num; + } else { + buffer->start = (buffer->start + 1) % FRAME_WINDOW_SIZE; + } + const int new_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE; + FrameRecord *const record = &buffer->buf[new_idx]; + record->ts_start = ts_start; + record->ts_end = ts_end; + record->pic_size = pic_size; + record->frame_header_count = frame_header_count; + record->show_frame = show_frame; + record->show_existing_frame = show_existing_frame; + + return new_idx; +} + +// Count the number of frames encoded in the last "duration" ticks, in display +// time. +static int count_frames(const FrameWindowBuffer *const buffer, + int64_t duration) { + const int current_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE; + // Assume current frame is shown frame. + assert(buffer->buf[current_idx].show_frame); + + const int64_t current_time = buffer->buf[current_idx].ts_end; + const int64_t time_limit = AOMMAX(current_time - duration, 0); + int num_frames = 1; + int index = current_idx - 1; + for (int i = buffer->num - 2; i >= 0; --i, --index, ++num_frames) { + if (index < 0) index = FRAME_WINDOW_SIZE - 1; + const FrameRecord *const record = &buffer->buf[index]; + if (!record->show_frame) continue; + const int64_t ts_start = record->ts_start; + if (ts_start < time_limit) break; + } + + return num_frames; +} + +// Scan previously encoded frames and update level metrics accordingly. +static void scan_past_frames(const FrameWindowBuffer *const buffer, + int num_frames_to_scan, + AV1LevelSpec *const level_spec) { + const int num_frames_in_buffer = buffer->num; + int index = (buffer->start + num_frames_in_buffer - 1) % FRAME_WINDOW_SIZE; + int frame_headers = 0; + int64_t display_samples = 0; + int64_t decoded_samples = 0; + for (int i = 0; i < AOMMIN(num_frames_in_buffer, num_frames_to_scan); ++i) { + const FrameRecord *const record = &buffer->buf[index]; + if (!record->show_existing_frame) { + frame_headers += record->frame_header_count; + decoded_samples += record->pic_size; + } + if (record->show_frame) { + display_samples += record->pic_size; + } + --index; + if (index < 0) index = FRAME_WINDOW_SIZE - 1; + } + level_spec->max_header_rate = + AOMMAX(level_spec->max_header_rate, frame_headers); + level_spec->max_display_rate = + AOMMAX(level_spec->max_display_rate, display_samples); + level_spec->max_decode_rate = + AOMMAX(level_spec->max_decode_rate, decoded_samples); +} + +void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start, + int64_t ts_end) { + AV1_COMMON *const cm = &cpi->common; + const int upscaled_width = cm->superres_upscaled_width; + const int height = cm->height; + const int tile_cols = cm->tile_cols; + const int tile_rows = cm->tile_rows; + const int tiles = tile_cols * tile_rows; + const int luma_pic_size = upscaled_width * height; + const int frame_header_count = cpi->frame_header_count; + const int show_frame = cm->show_frame; + const int show_existing_frame = cm->show_existing_frame; + + // Store info. of current frame into FrameWindowBuffer. + FrameWindowBuffer *const buffer = &cpi->frame_window_buffer; + store_frame_record(ts_start, ts_end, luma_pic_size, frame_header_count, + show_frame, show_existing_frame, buffer); + // Count the number of frames encoded in the past 1 second. + const int encoded_frames_in_last_second = + show_frame ? count_frames(buffer, TICKS_PER_SEC) : 0; + + int max_tile_size; + int min_cropped_tile_width; + int min_cropped_tile_height; + int tile_width_is_valid; + get_tile_stats(cpi, &max_tile_size, &min_cropped_tile_width, + &min_cropped_tile_height, &tile_width_is_valid); + + const SequenceHeader *const seq_params = &cm->seq_params; + const BITSTREAM_PROFILE profile = seq_params->profile; + const int pic_size_profile_factor = + profile == PROFILE_0 ? 15 : (profile == PROFILE_1 ? 30 : 36); + const size_t frame_compressed_size = (size > 129 ? size - 128 : 1); + const size_t frame_uncompressed_size = + (luma_pic_size * pic_size_profile_factor) >> 3; + + aom_clear_system_state(); + const double compression_ratio = + frame_uncompressed_size / (double)frame_compressed_size; + const double total_time_encoded = + (cpi->last_end_time_stamp_seen - cpi->first_time_stamp_ever) / + (double)TICKS_PER_SEC; + + const int temporal_layer_id = cm->temporal_layer_id; + const int spatial_layer_id = cm->spatial_layer_id; + const int is_still_picture = seq_params->still_picture; + // update level_stats + // TODO(kyslov@) fix the implementation according to buffer model + for (int i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; ++i) { + if (!is_in_operating_point(seq_params->operating_point_idc[i], + temporal_layer_id, spatial_layer_id)) { + continue; + } + + AV1LevelInfo *const level_info = &cpi->level_info[i]; + AV1LevelStats *const level_stats = &level_info->level_stats; + + level_stats->max_tile_size = + AOMMAX(level_stats->max_tile_size, max_tile_size); + level_stats->min_cropped_tile_width = + AOMMIN(level_stats->min_cropped_tile_width, min_cropped_tile_width); + level_stats->min_cropped_tile_height = + AOMMIN(level_stats->min_cropped_tile_height, min_cropped_tile_height); + level_stats->tile_width_is_valid &= tile_width_is_valid; + level_stats->total_compressed_size += frame_compressed_size; + if (show_frame) level_stats->total_time_encoded = total_time_encoded; + level_stats->min_cr = AOMMIN(level_stats->min_cr, compression_ratio); + + // update level_spec + // TODO(kyslov@) update all spec fields + AV1LevelSpec *const level_spec = &level_info->level_spec; + level_spec->max_picture_size = + AOMMAX(level_spec->max_picture_size, luma_pic_size); + level_spec->max_h_size = + AOMMAX(level_spec->max_h_size, cm->superres_upscaled_width); + level_spec->max_v_size = AOMMAX(level_spec->max_v_size, height); + level_spec->max_tile_cols = AOMMAX(level_spec->max_tile_cols, tile_cols); + level_spec->max_tiles = AOMMAX(level_spec->max_tiles, tiles); + + if (show_frame) { + scan_past_frames(buffer, encoded_frames_in_last_second, level_spec); + } + + // Check whether target level is met. + const AV1_LEVEL target_seq_level_idx = cpi->target_seq_level_idx[i]; + if (target_seq_level_idx < SEQ_LEVELS) { + const AV1LevelSpec *const target_level_spec = + av1_level_defs + target_seq_level_idx; + const int tier = seq_params->tier[i]; + const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints( + target_level_spec, level_spec, level_stats, tier, is_still_picture); + if (fail_id != TARGET_LEVEL_OK) { + const int target_level_major = 2 + (target_seq_level_idx >> 2); + const int target_level_minor = target_seq_level_idx & 3; + aom_internal_error(&cm->error, AOM_CODEC_ERROR, + "Failed to encode to the target level %d_%d. %s", + target_level_major, target_level_minor, + level_fail_messages[fail_id]); + } + } + } +} + +aom_codec_err_t av1_get_seq_level_idx(const AV1_COMP *cpi, int *seq_level_idx) { + const SequenceHeader *const seq_params = &cpi->common.seq_params; + if (!cpi->keep_level_stats) { + for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) { + seq_level_idx[op] = (int)SEQ_LEVEL_MAX; + } + return AOM_CODEC_OK; + } + + const int is_still_picture = seq_params->still_picture; + for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) { + seq_level_idx[op] = (int)SEQ_LEVEL_MAX; + const int tier = seq_params->tier[op]; + const AV1LevelInfo *const level_info = &cpi->level_info[op]; + const AV1LevelStats *const level_stats = &level_info->level_stats; + const AV1LevelSpec *const level_spec = &level_info->level_spec; + for (int level = 0; level < SEQ_LEVELS; ++level) { + const AV1LevelSpec *const target_level_spec = av1_level_defs + level; + const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints( + target_level_spec, level_spec, level_stats, tier, is_still_picture); + if (fail_id == TARGET_LEVEL_OK) { + seq_level_idx[op] = level; + break; + } + } + } + + return AOM_CODEC_OK; +} diff --git a/third_party/aom/av1/encoder/level.h b/third_party/aom/av1/encoder/level.h new file mode 100644 index 0000000000..8fff600590 --- /dev/null +++ b/third_party/aom/av1/encoder/level.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019, 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. + */ + +#ifndef AOM_AV1_ENCODER_LEVEL_H_ +#define AOM_AV1_ENCODER_LEVEL_H_ + +#include "av1/common/enums.h" + +struct AV1_COMP; + +// AV1 Level Specifications +typedef struct { + AV1_LEVEL level; + int max_picture_size; + int max_h_size; + int max_v_size; + int max_header_rate; + int max_tiles; + int max_tile_cols; + int64_t max_display_rate; + int64_t max_decode_rate; + double main_mbps; + double high_mbps; + double main_cr; + double high_cr; +} AV1LevelSpec; + +typedef struct { + int64_t ts_start; + int64_t ts_end; + int pic_size; + int frame_header_count; + int show_frame; + int show_existing_frame; +} FrameRecord; + +// Record frame info. in a rolling window. +#define FRAME_WINDOW_SIZE 256 +typedef struct { + FrameRecord buf[FRAME_WINDOW_SIZE]; + int num; // Number of FrameRecord stored in the buffer. + int start; // Buffer index of the first FrameRecord. +} FrameWindowBuffer; + +// Used to keep track of AV1 Level Stats. Currently unimplemented. +typedef struct { + uint64_t total_compressed_size; + int max_tile_size; + int min_cropped_tile_width; + int min_cropped_tile_height; + int tile_width_is_valid; + double total_time_encoded; + double min_cr; +} AV1LevelStats; + +typedef struct { + AV1LevelStats level_stats; + AV1LevelSpec level_spec; +} AV1LevelInfo; + +void av1_update_level_info(struct AV1_COMP *cpi, size_t size, int64_t ts_start, + int64_t ts_end); + +// Return sequence level indices in seq_level_idx[MAX_NUM_OPERATING_POINTS]. +aom_codec_err_t av1_get_seq_level_idx(const struct AV1_COMP *cpi, + int *seq_level_idx); + +#endif // AOM_AV1_ENCODER_LEVEL_H_ diff --git a/third_party/aom/av1/encoder/lookahead.c b/third_party/aom/av1/encoder/lookahead.c index fe3bc20512..f5298f7837 100644 --- a/third_party/aom/av1/encoder/lookahead.c +++ b/third_party/aom/av1/encoder/lookahead.c @@ -44,7 +44,7 @@ void av1_lookahead_destroy(struct lookahead_ctx *ctx) { struct lookahead_ctx *av1_lookahead_init( unsigned int width, unsigned int height, unsigned int subsampling_x, unsigned int subsampling_y, int use_highbitdepth, unsigned int depth, - const int border_in_pixels) { + const int border_in_pixels, int is_scale) { struct lookahead_ctx *ctx = NULL; // Clamp the lookahead queue depth @@ -62,10 +62,19 @@ struct lookahead_ctx *av1_lookahead_init( ctx->buf = calloc(depth, sizeof(*ctx->buf)); if (!ctx->buf) goto bail; for (i = 0; i < depth; i++) - if (aom_alloc_frame_buffer(&ctx->buf[i].img, width, height, subsampling_x, - subsampling_y, use_highbitdepth, - border_in_pixels, legacy_byte_alignment)) - goto bail; + if (is_scale) { + if (aom_alloc_frame_buffer( + &ctx->buf[i].img, width, height, subsampling_x, subsampling_y, + use_highbitdepth, border_in_pixels, legacy_byte_alignment)) + goto bail; + } else { + aom_free_frame_buffer(&ctx->buf[i].img); + if (aom_realloc_lookahead_buffer( + &ctx->buf[i].img, width, height, subsampling_x, subsampling_y, + use_highbitdepth, AOM_ENC_LOOKAHEAD_BORDER, + legacy_byte_alignment, NULL, NULL, NULL)) + goto bail; + } } return ctx; bail: diff --git a/third_party/aom/av1/encoder/lookahead.h b/third_party/aom/av1/encoder/lookahead.h index e5d9702443..3b2d94b08e 100644 --- a/third_party/aom/av1/encoder/lookahead.h +++ b/third_party/aom/av1/encoder/lookahead.h @@ -47,7 +47,7 @@ struct lookahead_ctx { struct lookahead_ctx *av1_lookahead_init( unsigned int width, unsigned int height, unsigned int subsampling_x, unsigned int subsampling_y, int use_highbitdepth, unsigned int depth, - const int border_in_pixels); + const int border_in_pixels, int is_scale); /**\brief Destroys the lookahead stage */ diff --git a/third_party/aom/av1/encoder/mcomp.c b/third_party/aom/av1/encoder/mcomp.c index 1bab45c7f1..c9573bdedd 100644 --- a/third_party/aom/av1/encoder/mcomp.c +++ b/third_party/aom/av1/encoder/mcomp.c @@ -19,6 +19,7 @@ #include "aom_dsp/aom_dsp_common.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" +#include "aom_ports/system_state.h" #include "av1/common/common.h" #include "av1/common/mvref_common.h" @@ -28,6 +29,7 @@ #include "av1/encoder/encoder.h" #include "av1/encoder/encodemv.h" #include "av1/encoder/mcomp.h" +#include "av1/encoder/partition_strategy.h" #include "av1/encoder/rdopt.h" #include "av1/encoder/reconinter_enc.h" @@ -1798,11 +1800,11 @@ static int full_pixel_diamond(const AV1_COMP *const cpi, MACROBLOCK *x, MV *mvp_full, int step_param, int sadpb, int further_steps, int do_refine, int *cost_list, const aom_variance_fn_ptr_t *fn_ptr, - const MV *ref_mv) { + const MV *ref_mv, const search_site_config *cfg) { MV temp_mv; int thissme, n, num00 = 0; - int bestsme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv, - step_param, sadpb, &n, fn_ptr, ref_mv); + int bestsme = cpi->diamond_search_sad(x, cfg, mvp_full, &temp_mv, step_param, + sadpb, &n, fn_ptr, ref_mv); if (bestsme < INT_MAX) bestsme = av1_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1); x->best_mv.as_mv = temp_mv; @@ -1817,9 +1819,9 @@ static int full_pixel_diamond(const AV1_COMP *const cpi, MACROBLOCK *x, if (num00) { num00--; } else { - thissme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv, - step_param + n, sadpb, &num00, fn_ptr, - ref_mv); + thissme = + cpi->diamond_search_sad(x, cfg, mvp_full, &temp_mv, step_param + n, + sadpb, &num00, fn_ptr, ref_mv); if (thissme < INT_MAX) thissme = av1_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1); @@ -2095,11 +2097,222 @@ static int is_exhaustive_allowed(const AV1_COMP *const cpi, MACROBLOCK *x) { return is_allowed; } +static int vector_match(int16_t *ref, int16_t *src, int bwl) { + int best_sad = INT_MAX; + int this_sad; + int d; + int center, offset = 0; + int bw = 4 << bwl; // redundant variable, to be changed in the experiments. + for (d = 0; d <= bw; d += 16) { + this_sad = aom_vector_var(&ref[d], src, bwl); + if (this_sad < best_sad) { + best_sad = this_sad; + offset = d; + } + } + center = offset; + + for (d = -8; d <= 8; d += 16) { + int this_pos = offset + d; + // check limit + if (this_pos < 0 || this_pos > bw) continue; + this_sad = aom_vector_var(&ref[this_pos], src, bwl); + if (this_sad < best_sad) { + best_sad = this_sad; + center = this_pos; + } + } + offset = center; + + for (d = -4; d <= 4; d += 8) { + int this_pos = offset + d; + // check limit + if (this_pos < 0 || this_pos > bw) continue; + this_sad = aom_vector_var(&ref[this_pos], src, bwl); + if (this_sad < best_sad) { + best_sad = this_sad; + center = this_pos; + } + } + offset = center; + + for (d = -2; d <= 2; d += 4) { + int this_pos = offset + d; + // check limit + if (this_pos < 0 || this_pos > bw) continue; + this_sad = aom_vector_var(&ref[this_pos], src, bwl); + if (this_sad < best_sad) { + best_sad = this_sad; + center = this_pos; + } + } + offset = center; + + for (d = -1; d <= 1; d += 2) { + int this_pos = offset + d; + // check limit + if (this_pos < 0 || this_pos > bw) continue; + this_sad = aom_vector_var(&ref[this_pos], src, bwl); + if (this_sad < best_sad) { + best_sad = this_sad; + center = this_pos; + } + } + + return (center - (bw >> 1)); +} + +static const MV search_pos[4] = { + { -1, 0 }, + { 0, -1 }, + { 0, 1 }, + { 1, 0 }, +}; + +unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int mi_row, + int mi_col, const MV *ref_mv) { + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mi = xd->mi[0]; + struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } }; + DECLARE_ALIGNED(16, int16_t, hbuf[256]); + DECLARE_ALIGNED(16, int16_t, vbuf[256]); + DECLARE_ALIGNED(16, int16_t, src_hbuf[128]); + DECLARE_ALIGNED(16, int16_t, src_vbuf[128]); + int idx; + const int bw = 4 << mi_size_wide_log2[bsize]; + const int bh = 4 << mi_size_high_log2[bsize]; + const int search_width = bw << 1; + const int search_height = bh << 1; + const int src_stride = x->plane[0].src.stride; + const int ref_stride = xd->plane[0].pre[0].stride; + uint8_t const *ref_buf, *src_buf; + MV *tmp_mv = &xd->mi[0]->mv[0].as_mv; + unsigned int best_sad, tmp_sad, this_sad[4]; + MV this_mv; + const int norm_factor = 3 + (bw >> 5); + const YV12_BUFFER_CONFIG *scaled_ref_frame = + av1_get_scaled_ref_frame(cpi, mi->ref_frame[0]); + MvLimits subpel_mv_limits; + + if (scaled_ref_frame) { + int i; + // Swap out the reference frame for a version that's been scaled to + // match the resolution of the current frame, allowing the existing + // motion search code to be used without additional modifications. + for (i = 0; i < MAX_MB_PLANE; i++) backup_yv12[i] = xd->plane[i].pre[0]; + av1_setup_pre_planes(xd, 0, scaled_ref_frame, mi_row, mi_col, NULL, + MAX_MB_PLANE); + } + + if (xd->bd != 8) { + unsigned int sad; + tmp_mv->row = 0; + tmp_mv->col = 0; + sad = cpi->fn_ptr[bsize].sdf(x->plane[0].src.buf, src_stride, + xd->plane[0].pre[0].buf, ref_stride); + + if (scaled_ref_frame) { + int i; + for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[0] = backup_yv12[i]; + } + return sad; + } + + // Set up prediction 1-D reference set + ref_buf = xd->plane[0].pre[0].buf - (bw >> 1); + for (idx = 0; idx < search_width; idx += 16) { + aom_int_pro_row(&hbuf[idx], ref_buf, ref_stride, bh); + ref_buf += 16; + } + + ref_buf = xd->plane[0].pre[0].buf - (bh >> 1) * ref_stride; + for (idx = 0; idx < search_height; ++idx) { + vbuf[idx] = aom_int_pro_col(ref_buf, bw) >> norm_factor; + ref_buf += ref_stride; + } + + // Set up src 1-D reference set + for (idx = 0; idx < bw; idx += 16) { + src_buf = x->plane[0].src.buf + idx; + aom_int_pro_row(&src_hbuf[idx], src_buf, src_stride, bh); + } + + src_buf = x->plane[0].src.buf; + for (idx = 0; idx < bh; ++idx) { + src_vbuf[idx] = aom_int_pro_col(src_buf, bw) >> norm_factor; + src_buf += src_stride; + } + + // Find the best match per 1-D search + tmp_mv->col = vector_match(hbuf, src_hbuf, mi_size_wide_log2[bsize]); + tmp_mv->row = vector_match(vbuf, src_vbuf, mi_size_high_log2[bsize]); + + this_mv = *tmp_mv; + src_buf = x->plane[0].src.buf; + ref_buf = xd->plane[0].pre[0].buf + this_mv.row * ref_stride + this_mv.col; + best_sad = cpi->fn_ptr[bsize].sdf(src_buf, src_stride, ref_buf, ref_stride); + + { + const uint8_t *const pos[4] = { + ref_buf - ref_stride, + ref_buf - 1, + ref_buf + 1, + ref_buf + ref_stride, + }; + + cpi->fn_ptr[bsize].sdx4df(src_buf, src_stride, pos, ref_stride, this_sad); + } + + for (idx = 0; idx < 4; ++idx) { + if (this_sad[idx] < best_sad) { + best_sad = this_sad[idx]; + tmp_mv->row = search_pos[idx].row + this_mv.row; + tmp_mv->col = search_pos[idx].col + this_mv.col; + } + } + + if (this_sad[0] < this_sad[3]) + this_mv.row -= 1; + else + this_mv.row += 1; + + if (this_sad[1] < this_sad[2]) + this_mv.col -= 1; + else + this_mv.col += 1; + + ref_buf = xd->plane[0].pre[0].buf + this_mv.row * ref_stride + this_mv.col; + + tmp_sad = cpi->fn_ptr[bsize].sdf(src_buf, src_stride, ref_buf, ref_stride); + if (best_sad > tmp_sad) { + *tmp_mv = this_mv; + best_sad = tmp_sad; + } + + tmp_mv->row *= 8; + tmp_mv->col *= 8; + + set_subpel_mv_search_range( + &x->mv_limits, &subpel_mv_limits.col_min, &subpel_mv_limits.col_max, + &subpel_mv_limits.row_min, &subpel_mv_limits.row_max, ref_mv); + clamp_mv(tmp_mv, subpel_mv_limits.col_min, subpel_mv_limits.col_max, + subpel_mv_limits.row_min, subpel_mv_limits.row_max); + + if (scaled_ref_frame) { + int i; + for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[0] = backup_yv12[i]; + } + + return best_sad; +} + int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, MV *mvp_full, int step_param, int method, int run_mesh_search, int error_per_bit, int *cost_list, const MV *ref_mv, int var_max, int rd, - int x_pos, int y_pos, int intra) { + int x_pos, int y_pos, int intra, + const search_site_config *cfg) { const SPEED_FEATURES *const sf = &cpi->sf; const aom_variance_fn_ptr_t *fn_ptr = &cpi->fn_ptr[bsize]; int var = 0; @@ -2139,7 +2352,7 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, case NSTEP: var = full_pixel_diamond(cpi, x, mvp_full, step_param, error_per_bit, MAX_MVSEARCH_STEPS - 1 - step_param, 1, - cost_list, fn_ptr, ref_mv); + cost_list, fn_ptr, ref_mv, cfg); // Should we allow a follow on exhaustive search? if (is_exhaustive_allowed(cpi, x)) { @@ -2676,14 +2889,15 @@ static int obmc_full_pixel_diamond(const AV1_COMP *cpi, MACROBLOCK *x, MV *mvp_full, int step_param, int sadpb, int further_steps, int do_refine, const aom_variance_fn_ptr_t *fn_ptr, - const MV *ref_mv, MV *dst_mv, - int is_second) { + const MV *ref_mv, MV *dst_mv, int is_second, + const search_site_config *cfg) { + (void)cpi; // to silence compiler warning const int32_t *wsrc = x->wsrc_buf; const int32_t *mask = x->mask_buf; MV temp_mv; int thissme, n, num00 = 0; int bestsme = - obmc_diamond_search_sad(x, &cpi->ss_cfg, wsrc, mask, mvp_full, &temp_mv, + obmc_diamond_search_sad(x, cfg, wsrc, mask, mvp_full, &temp_mv, step_param, sadpb, &n, fn_ptr, ref_mv, is_second); if (bestsme < INT_MAX) bestsme = get_obmc_mvpred_var(x, wsrc, mask, &temp_mv, ref_mv, fn_ptr, 1, @@ -2700,9 +2914,9 @@ static int obmc_full_pixel_diamond(const AV1_COMP *cpi, MACROBLOCK *x, if (num00) { num00--; } else { - thissme = obmc_diamond_search_sad(x, &cpi->ss_cfg, wsrc, mask, mvp_full, - &temp_mv, step_param + n, sadpb, &num00, - fn_ptr, ref_mv, is_second); + thissme = obmc_diamond_search_sad(x, cfg, wsrc, mask, mvp_full, &temp_mv, + step_param + n, sadpb, &num00, fn_ptr, + ref_mv, is_second); if (thissme < INT_MAX) thissme = get_obmc_mvpred_var(x, wsrc, mask, &temp_mv, ref_mv, fn_ptr, 1, is_second); @@ -2738,11 +2952,12 @@ int av1_obmc_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, MV *mvp_full, int step_param, int sadpb, int further_steps, int do_refine, const aom_variance_fn_ptr_t *fn_ptr, - const MV *ref_mv, MV *dst_mv, int is_second) { + const MV *ref_mv, MV *dst_mv, int is_second, + const search_site_config *cfg) { if (cpi->sf.obmc_full_pixel_search_level == 0) { return obmc_full_pixel_diamond(cpi, x, mvp_full, step_param, sadpb, further_steps, do_refine, fn_ptr, ref_mv, - dst_mv, is_second); + dst_mv, is_second, cfg); } else { const int32_t *wsrc = x->wsrc_buf; const int32_t *mask = x->mask_buf; @@ -2851,3 +3066,117 @@ int av1_return_min_sub_pixel_mv( lower_mv_precision(bestmv, allow_hp, 0); return besterr; } + +void av1_simple_motion_search(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, + int mi_col, BLOCK_SIZE bsize, int ref, + MV ref_mv_full, int num_planes, + int use_subpixel) { + assert(num_planes == 1 && + "Currently simple_motion_search only supports luma plane"); + assert(!frame_is_intra_only(&cpi->common) && + "Simple motion search only enabled for non-key frames"); + AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + + set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize); + + MB_MODE_INFO *mbmi = xd->mi[0]; + mbmi->sb_type = bsize; + mbmi->ref_frame[0] = ref; + mbmi->ref_frame[1] = NONE_FRAME; + mbmi->motion_mode = SIMPLE_TRANSLATION; + + const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref); + const YV12_BUFFER_CONFIG *scaled_ref_frame = + av1_get_scaled_ref_frame(cpi, ref); + struct buf_2d backup_yv12; + // ref_mv is used to code the motion vector. ref_mv_full is the initial point. + // ref_mv is in units of 1/8 pel whereas ref_mv_full is in units of pel. + MV ref_mv = { 0, 0 }; + const int step_param = cpi->mv_step_param; + const MvLimits tmp_mv_limits = x->mv_limits; + const SEARCH_METHODS search_methods = NSTEP; + const int do_mesh_search = 0; + const int sadpb = x->sadperbit16; + int cost_list[5]; + const int ref_idx = 0; + int var; + + if (scaled_ref_frame) { + backup_yv12 = xd->plane[AOM_PLANE_Y].pre[ref_idx]; + av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL, + num_planes); + } else { + av1_setup_pre_planes(xd, ref_idx, yv12, mi_row, mi_col, + get_ref_scale_factors(cm, ref), num_planes); + } + + // This overwrites the mv_limits so we will need to restore it later. + av1_set_mv_search_range(&x->mv_limits, &ref_mv); + var = av1_full_pixel_search( + cpi, x, bsize, &ref_mv_full, step_param, search_methods, do_mesh_search, + sadpb, cond_cost_list(cpi, cost_list), &ref_mv, INT_MAX, 1, + mi_col * MI_SIZE, mi_row * MI_SIZE, 0, &cpi->ss_cfg[SS_CFG_SRC]); + // Restore + x->mv_limits = tmp_mv_limits; + + const int use_subpel_search = + var < INT_MAX && !cpi->common.cur_frame_force_integer_mv && use_subpixel; + if (use_subpel_search) { + int not_used = 0; + if (cpi->sf.use_accurate_subpel_search) { + const int pw = block_size_wide[bsize]; + const int ph = block_size_high[bsize]; + cpi->find_fractional_mv_step( + x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv, + x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop, + cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list), + x->nmv_vec_cost, x->mv_cost_stack, ¬_used, &x->pred_sse[ref], NULL, + NULL, 0, 0, pw, ph, cpi->sf.use_accurate_subpel_search, 1); + } else { + cpi->find_fractional_mv_step( + x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv, + x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop, + cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list), + x->nmv_vec_cost, x->mv_cost_stack, ¬_used, &x->pred_sse[ref], NULL, + NULL, 0, 0, 0, 0, 0, 1); + } + } else { + // Manually convert from units of pixel to 1/8-pixels if we are not doing + // subpel search + x->best_mv.as_mv.row *= 8; + x->best_mv.as_mv.col *= 8; + } + + mbmi->mv[0].as_mv = x->best_mv.as_mv; + + // Get a copy of the prediction output + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + + aom_clear_system_state(); + + if (scaled_ref_frame) { + xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12; + } +} + +void av1_simple_motion_sse_var(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, + int mi_col, BLOCK_SIZE bsize, + const MV ref_mv_full, int use_subpixel, + unsigned int *sse, unsigned int *var) { + MACROBLOCKD *xd = &x->e_mbd; + const MV_REFERENCE_FRAME ref = + cpi->rc.is_src_frame_alt_ref ? ALTREF_FRAME : LAST_FRAME; + + av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, ref_mv_full, 1, + use_subpixel); + + const uint8_t *src = x->plane[0].src.buf; + const int src_stride = x->plane[0].src.stride; + const uint8_t *dst = xd->plane[0].dst.buf; + const int dst_stride = xd->plane[0].dst.stride; + + *var = cpi->fn_ptr[bsize].vf(src, src_stride, dst, dst_stride, sse); +} diff --git a/third_party/aom/av1/encoder/mcomp.h b/third_party/aom/av1/encoder/mcomp.h index 3f8b3b1fd3..71547da8d9 100644 --- a/third_party/aom/av1/encoder/mcomp.h +++ b/third_party/aom/av1/encoder/mcomp.h @@ -13,6 +13,7 @@ #define AOM_AV1_ENCODER_MCOMP_H_ #include "av1/encoder/block.h" + #include "aom_dsp/variance.h" #ifdef __cplusplus @@ -83,6 +84,11 @@ int av1_refining_search_sad(struct macroblock *x, MV *ref_mv, int sad_per_bit, int distance, const aom_variance_fn_ptr_t *fn_ptr, const MV *center_mv); +unsigned int av1_int_pro_motion_estimation(const struct AV1_COMP *cpi, + MACROBLOCK *x, BLOCK_SIZE bsize, + int mi_row, int mi_col, + const MV *ref_mv); + // Runs sequence of diamond searches in smaller steps for RD. int av1_full_pixel_diamond(const struct AV1_COMP *cpi, MACROBLOCK *x, MV *mvp_full, int step_param, int sadpb, @@ -132,13 +138,15 @@ int av1_full_pixel_search(const struct AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, MV *mvp_full, int step_param, int method, int run_mesh_search, int error_per_bit, int *cost_list, const MV *ref_mv, int var_max, int rd, - int x_pos, int y_pos, int intra); + int x_pos, int y_pos, int intra, + const search_site_config *cfg); int av1_obmc_full_pixel_search(const struct AV1_COMP *cpi, MACROBLOCK *x, MV *mvp_full, int step_param, int sadpb, int further_steps, int do_refine, const aom_variance_fn_ptr_t *fn_ptr, - const MV *ref_mv, MV *dst_mv, int is_second); + const MV *ref_mv, MV *dst_mv, int is_second, + const search_site_config *cfg); int av1_find_best_obmc_sub_pixel_tree_up( MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, MV *bestmv, const MV *ref_mv, int allow_hp, int error_per_bit, @@ -154,6 +162,19 @@ unsigned int av1_refine_warped_mv(const struct AV1_COMP *cpi, int mi_row, int mi_col, int *pts0, int *pts_inref0, int total_samples); +// Performs a motion search in SIMPLE_TRANSLATION mode using reference frame +// ref. Note that this sets the offset of mbmi, so we will need to reset it +// after calling this function. +void av1_simple_motion_search(struct AV1_COMP *const cpi, MACROBLOCK *x, + int mi_row, int mi_col, BLOCK_SIZE bsize, int ref, + MV ref_mv_full, int num_planes, int use_subpixel); + +// Performs a simple motion search to calculate the sse and var of the residue +void av1_simple_motion_sse_var(struct AV1_COMP *cpi, MACROBLOCK *x, int mi_row, + int mi_col, BLOCK_SIZE bsize, + const MV ref_mv_full, int use_subpixel, + unsigned int *sse, unsigned int *var); + static INLINE void av1_set_fractional_mv(int_mv *fractional_best_mv) { for (int z = 0; z < 3; z++) { fractional_best_mv[z].as_int = INVALID_MV; diff --git a/third_party/aom/av1/encoder/partition_model_weights.h b/third_party/aom/av1/encoder/partition_model_weights.h index 2e7b2c62af..b754c88813 100644 --- a/third_party/aom/av1/encoder/partition_model_weights.h +++ b/third_party/aom/av1/encoder/partition_model_weights.h @@ -2441,143 +2441,12 @@ static const NN_CONFIG av1_rect_partition_nnconfig_128 = { #undef NUM_NODES #undef LABEL_SIZE -#if CONFIG_ONE_PASS_SVM -#define FEATURE_SIZE 24 -static const float av1_op_svm_early_term_weights_128[FEATURE_SIZE + 1] = { - -4.5893036051f, 6.9065208136f, -9.1579514692f, 0.1353151366f, - -1.0271889653f, -0.0020988254f, -0.0094355949f, 0.0040209656f, - 0.0073014747f, 0.7939705382f, 0.0254545714f, 0.0557559708f, - -0.0339662064f, -0.0496818300f, 0.3053600283f, 0.3699486845f, - 0.0848271391f, 0.4091075988f, 0.1196729398f, -0.0038137193f, - -0.0773495909f, -0.0651630642f, -0.0123704995f, -0.0036697401f, - -4.1930227095f, -}; - -static const float av1_op_svm_early_term_weights_64[FEATURE_SIZE + 1] = { - -2.7600454480f, 5.6822046712f, -6.7576830133f, 0.1326457117f, - -1.0541818372f, 0.0107782654f, 0.0050469147f, -0.0021362631f, - -0.0135151040f, -0.1020115005f, -0.0283409957f, -0.0176311233f, - 0.0250648204f, 0.0196228570f, 0.5441528594f, 0.2767320141f, - 0.1261231351f, 0.2998476408f, 0.1336215695f, -0.1107823946f, - -0.0697279598f, -0.0577520545f, -0.0558441075f, -0.0699750617f, - -2.6995991503f, -}; - -static const float av1_op_svm_early_term_weights_32[FEATURE_SIZE + 1] = { - -0.8950734172f, 1.3559565008f, -2.6733642653f, 0.2661361319f, - -0.0314731140f, 0.0044943456f, 0.0006438044f, -0.0029066686f, - -0.0021903213f, 0.5845049496f, -0.0003629350f, 0.0006982840f, - 0.0014157386f, -0.0017427528f, 0.7078456733f, 0.1600998068f, - 0.0933852747f, 0.2822125876f, 0.1923826165f, -0.0905903459f, - -0.0564717590f, -0.0591007486f, -0.0692268554f, -0.0677411981f, - -0.7101853206f, -}; - -static const float av1_op_svm_early_term_weights_16[FEATURE_SIZE + 1] = { - -0.1719124013f, -0.3192305362f, -1.1714597182f, 0.4437770294f, - -0.0042344643f, 0.0000027764f, 0.0018827450f, -0.0015555613f, - -0.0003250050f, 0.9413693294f, 0.0076188418f, -0.0067870352f, - 0.0006329246f, -0.0013059613f, 0.8596697254f, 0.0635558018f, - 0.0447224598f, 0.0915706321f, 0.0741662273f, -0.0269096547f, - -0.0244610614f, -0.0281113318f, -0.0326108845f, -0.0350908892f, - -0.0307521675f, -}; - -static const float av1_op_svm_early_term_mean_128[FEATURE_SIZE] = { - 940540.3259649610f, 3988285.5905584921f, 575475302.3545289040f, - 0.5775348803f, 866.9828469502f, 0.2503762393f, - 0.2501466215f, 0.2513213770f, 0.2481557622f, - 521994448.3219169378f, 0.2666920631f, 0.2535864361f, - 0.2481589186f, 0.2315625823f, 100519.1049708007f, - 12.1299754840f, 0.8279971004f, 12.6664603305f, - 0.7313258998f, 935.8233056680f, 0.7436563032f, - 0.7710055018f, 0.7376516970f, 0.6859818720f, -}; - -static const float av1_op_svm_early_term_mean_64[FEATURE_SIZE] = { - 420419.7529613562f, 839754.4414347620f, 129360420.5256031156f, - 0.6525652037f, 548.8972009954f, 0.2506918565f, - 0.2488349076f, 0.2501724146f, 0.2503008213f, - 113132974.7944754064f, 0.2479344278f, 0.2471446791f, - 0.2524478512f, 0.2524730419f, 91147.9854189453f, - 10.9642508460f, 0.8936554428f, 11.3877865621f, - 0.8307555282f, 752.7787491956f, 0.7243363939f, - 0.7198362119f, 0.7329432336f, 0.7245090283f, -}; - -static const float av1_op_svm_early_term_mean_32[FEATURE_SIZE] = { - 105111.0236438536f, 184296.0939716828f, 29117017.6751756854f, - 0.6402298612f, 140.2223339218f, 0.2495860872f, - 0.2496407600f, 0.2506238629f, 0.2501492900f, - 24480304.9390618578f, 0.2494442027f, 0.2496080963f, - 0.2504881563f, 0.2504595447f, 60297.6762059058f, - 9.4279752138f, 0.9287901132f, 9.6516813792f, - 0.9009173677f, 591.5406335030f, 0.6944486917f, - 0.6983941982f, 0.6927236901f, 0.6921613649f, -}; - -static const float av1_op_svm_early_term_mean_16[FEATURE_SIZE] = { - 34080.7994802934f, 44108.1176228864f, 7494288.4946180154f, 0.6240636218f, - 36.4539515827f, 0.2490867417f, 0.2499231014f, 0.2505361492f, - 0.2504540077f, 5913397.2957480755f, 0.2487482536f, 0.2495500728f, - 0.2503693302f, 0.2513323434f, 36574.9686737814f, 7.4345592768f, - 0.9592429205f, 7.6001764585f, 0.9459867777f, 490.4635033056f, - 0.6626215237f, 0.6580791886f, 0.6655481064f, 0.6589010119f, -}; - -static const float av1_op_svm_early_term_std_128[FEATURE_SIZE] = { - 2054266.2732957317f, 7550554.6241466375f, 1078688147.1656334400f, - 0.4939517611f, 1414.3139592985f, 0.1504634077f, - 0.1515907199f, 0.1590329744f, 0.1515653324f, - 1006422867.8989596367f, 0.1168668155f, 0.1195725959f, - 0.1195825693f, 0.1123065533f, 195261.0940245980f, - 4.5876675121f, 0.3773829648f, 4.8017339769f, - 0.4432700397f, 973.7532938848f, 0.4790027843f, - 0.5056275222f, 0.5262278749f, 0.4685586148f, -}; - -static const float av1_op_svm_early_term_std_64[FEATURE_SIZE] = { - 1093636.0522712648f, 1749863.5221569177f, 255168612.8025657237f, - 0.4761552884f, 1084.7927994662f, 0.1099344646f, - 0.1100619440f, 0.1090853225f, 0.1115303745f, - 232084513.1365262568f, 0.0759732385f, 0.0762942913f, - 0.0785624106f, 0.0779284747f, 185687.9441778057f, - 4.4371901245f, 0.3082781088f, 4.6670562831f, - 0.3749677061f, 854.3212307408f, 0.4920531348f, - 0.5073919158f, 0.5054698298f, 0.4904895620f, -}; - -static const float av1_op_svm_early_term_std_32[FEATURE_SIZE] = { - 238229.7484988807f, 400136.8703966461f, 60267828.4581554681f, - 0.4799328974f, 268.9377064297f, 0.1122938575f, - 0.1126479260f, 0.1137018559f, 0.1126389337f, - 52174139.1477040648f, 0.0715628767f, 0.0720997035f, - 0.0728961434f, 0.0732065300f, 147785.0049793872f, - 4.2092341484f, 0.2571751131f, 4.3893075417f, - 0.2987729310f, 769.0253148602f, 0.5027558039f, - 0.4982811444f, 0.5092312751f, 0.4991214994f, -}; - -static const float av1_op_svm_early_term_std_16[FEATURE_SIZE] = { - 64177.9527087587f, 103729.9987511119f, 16632490.8146969266f, - 0.4843637247f, 65.8114470725f, 0.0884226846f, - 0.0912638659f, 0.0914771167f, 0.0916078800f, - 13364581.3877149168f, 0.0677468925f, 0.0689631274f, - 0.0689915367f, 0.0702648469f, 111397.2620676765f, - 3.7858187888f, 0.1977269328f, 3.9420183951f, - 0.2260437881f, 717.5336868275f, 0.5017939514f, - 0.5066633533f, 0.5086806985f, 0.5085585987f, -}; - -#undef FEATURE_SIZE -#endif // CONFIG_ONE_PASS_SVM - -// Below are the models used for full_pixel_motion_search_based_split -static const float full_pixel_motion_search_based_split_thresh_128 = 2.0f; -static const float full_pixel_motion_search_based_split_thresh_64 = 2.0f; -static const float full_pixel_motion_search_based_split_thresh_32 = 2.0f; -static const float full_pixel_motion_search_based_split_thresh_16 = 2.0f; -static const float full_pixel_motion_search_based_split_thresh_8 = 2.0f; +// Below are the models used for simple_motion_search_based_split +static const float av1_simple_motion_search_based_split_thresh_128 = 2.0f; +static const float av1_simple_motion_search_based_split_thresh_64 = 2.0f; +static const float av1_simple_motion_search_based_split_thresh_32 = 2.0f; +static const float av1_simple_motion_search_based_split_thresh_16 = 2.0f; +static const float av1_simple_motion_search_based_split_thresh_8 = 2.0f; // BLOCK_128X128 #define NUM_HIDDEN_LAYERS_128 1 @@ -2585,7 +2454,7 @@ static const float full_pixel_motion_search_based_split_thresh_8 = 2.0f; #define NUM_LAYER_0_UNITS_128 16 #define NUM_LOGITS_128 1 -static const float full_pixel_motion_search_based_split_layer_0_kernel_128[] = { +static const float av1_simple_motion_search_based_split_layer_0_kernel_128[] = { -0.807346f, 0.242298f, 12.9862f, -1.19161f, 5.21734f, -1.1363f, -2.39127f, 0.930915f, -2.44285f, -2.42966f, 5.73476f, 0.0506879f, -0.234878f, -0.317875f, 0.361322f, 0.431648f, -0.39105f, -0.110225f, @@ -2604,23 +2473,23 @@ static const float full_pixel_motion_search_based_split_layer_0_kernel_128[] = { 0.702545f, -0.612227f, -7.68881f, 9.52225f, -1.18581f, -2.56762f }; -static const float full_pixel_motion_search_based_split_logits_kernel_128[] = { +static const float av1_simple_motion_search_based_split_logits_kernel_128[] = { 0.364895f, 0.577553f, 0.115758f, -0.999496f, 0.124885f, 3.23193f, -0.00386642f, 0.970794f, 0.136637f, -4.28052f, -1.49234f, 0.370436f, 0.576981f, -0.469656f, -0.124071f, 1.07669f }; -static const float full_pixel_motion_search_based_split_layer_0_bias_128[] = { +static const float av1_simple_motion_search_based_split_layer_0_bias_128[] = { 1.32916f, 0.817212f, 0.0f, -0.921066f, 0.0f, 3.57649f, -0.0204517f, 2.97286f, 0.0f, 5.49957f, -8.14518f, 0.0f, 1.30826f, -0.349536f, -0.638933f, 5.4496f }; -static const float full_pixel_motion_search_based_split_logits_bias_128[] = { +static const float av1_simple_motion_search_based_split_logits_bias_128[] = { 0.683442f }; -static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_128 = { +static const NN_CONFIG av1_simple_motion_search_based_split_nn_config_128 = { NUM_FEATURES_128, NUM_LOGITS_128, NUM_HIDDEN_LAYERS_128, @@ -2628,12 +2497,12 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_128 = { NUM_LAYER_0_UNITS_128, }, { - full_pixel_motion_search_based_split_layer_0_kernel_128, - full_pixel_motion_search_based_split_logits_kernel_128, + av1_simple_motion_search_based_split_layer_0_kernel_128, + av1_simple_motion_search_based_split_logits_kernel_128, }, { - full_pixel_motion_search_based_split_layer_0_bias_128, - full_pixel_motion_search_based_split_logits_bias_128, + av1_simple_motion_search_based_split_layer_0_bias_128, + av1_simple_motion_search_based_split_logits_bias_128, }, }; @@ -2648,7 +2517,7 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_128 = { #define NUM_LAYER_0_UNITS_64 16 #define NUM_LOGITS_64 1 -static const float full_pixel_motion_search_based_split_layer_0_kernel_64[] = { +static const float av1_simple_motion_search_based_split_layer_0_kernel_64[] = { 0.0345945f, -0.394064f, 0.0919978f, 0.270358f, -0.384502f, -0.504608f, -0.25759f, 0.155981f, 2.62567f, -10.7204f, -0.709802f, 8.15948f, 0.589866f, -0.445645f, -1.68232f, 10.0061f, -3.17671f, 4.87259f, @@ -2667,23 +2536,23 @@ static const float full_pixel_motion_search_based_split_layer_0_kernel_64[] = { -0.217072f, -0.0984913f, -0.265515f, 0.360021f, 0.0779512f, 0.361516f }; -static const float full_pixel_motion_search_based_split_logits_kernel_64[] = { +static const float av1_simple_motion_search_based_split_logits_kernel_64[] = { 0.470821f, 0.474747f, -0.571292f, 0.403221f, 0.628966f, -0.617029f, 0.501105f, 0.499962f, -1.5451f, -0.473518f, -0.730568f, -5.55817f, 0.776761f, 0.42569f, 0.311925f, 0.469968f }; -static const float full_pixel_motion_search_based_split_layer_0_bias_64[] = { +static const float av1_simple_motion_search_based_split_layer_0_bias_64[] = { -0.134085f, 0.0758715f, 1.10419f, 0.0f, -5.75737f, 1.65494f, 0.0f, 3.44047f, 0.394852f, 3.43858f, 3.65871f, -4.84987f, 1.21207f, -1.7705f, -5.46469f, -0.0889634f }; -static const float full_pixel_motion_search_based_split_logits_bias_64[] = { +static const float av1_simple_motion_search_based_split_logits_bias_64[] = { -0.479491f }; -static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_64 = { +static const NN_CONFIG av1_simple_motion_search_based_split_nn_config_64 = { NUM_FEATURES_64, NUM_LOGITS_64, NUM_HIDDEN_LAYERS_64, @@ -2691,12 +2560,12 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_64 = { NUM_LAYER_0_UNITS_64, }, { - full_pixel_motion_search_based_split_layer_0_kernel_64, - full_pixel_motion_search_based_split_logits_kernel_64, + av1_simple_motion_search_based_split_layer_0_kernel_64, + av1_simple_motion_search_based_split_logits_kernel_64, }, { - full_pixel_motion_search_based_split_layer_0_bias_64, - full_pixel_motion_search_based_split_logits_bias_64, + av1_simple_motion_search_based_split_layer_0_bias_64, + av1_simple_motion_search_based_split_logits_bias_64, }, }; @@ -2711,7 +2580,7 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_64 = { #define NUM_LAYER_0_UNITS_32 16 #define NUM_LOGITS_32 1 -static const float full_pixel_motion_search_based_split_layer_0_kernel_32[] = { +static const float av1_simple_motion_search_based_split_layer_0_kernel_32[] = { -1.61796f, 0.0585128f, 1.57904f, 1.52703f, 0.367779f, 0.220434f, 1.66652f, -1.77782f, 6.41118f, 4.16976f, 4.97299f, 4.84111f, -0.0956536f, -0.163284f, -0.143662f, 0.129329f, 0.449659f, -0.528844f, @@ -2730,23 +2599,23 @@ static const float full_pixel_motion_search_based_split_layer_0_kernel_32[] = { -1.91327f, -0.0356497f, 1.47611f, 1.27499f, -1.76108f, -0.578954f }; -static const float full_pixel_motion_search_based_split_logits_kernel_32[] = { +static const float av1_simple_motion_search_based_split_logits_kernel_32[] = { -0.220382f, -0.693902f, 0.424827f, 0.379952f, -0.413791f, -0.326785f, -0.455086f, 0.242402f, 0.307986f, 0.175746f, 0.498901f, -0.628053f, 0.285447f, 0.230052f, 0.415151f, -0.842946f }; -static const float full_pixel_motion_search_based_split_layer_0_bias_32[] = { +static const float av1_simple_motion_search_based_split_layer_0_bias_32[] = { -1.80751f, 6.40356f, -0.0512058f, -4.59163f, -0.369933f, -0.195755f, -0.16648f, -0.599755f, -5.35975f, -1.21349f, 2.48414f, 1.07096f, -3.66684f, -6.17761f, 4.2159f, -1.05286f }; -static const float full_pixel_motion_search_based_split_logits_bias_32[] = { +static const float av1_simple_motion_search_based_split_logits_bias_32[] = { -2.58676f }; -static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_32 = { +static const NN_CONFIG av1_simple_motion_search_based_split_nn_config_32 = { NUM_FEATURES_32, NUM_LOGITS_32, NUM_HIDDEN_LAYERS_32, @@ -2754,12 +2623,12 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_32 = { NUM_LAYER_0_UNITS_32, }, { - full_pixel_motion_search_based_split_layer_0_kernel_32, - full_pixel_motion_search_based_split_logits_kernel_32, + av1_simple_motion_search_based_split_layer_0_kernel_32, + av1_simple_motion_search_based_split_logits_kernel_32, }, { - full_pixel_motion_search_based_split_layer_0_bias_32, - full_pixel_motion_search_based_split_logits_bias_32, + av1_simple_motion_search_based_split_layer_0_bias_32, + av1_simple_motion_search_based_split_logits_bias_32, }, }; @@ -2774,7 +2643,7 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_32 = { #define NUM_LAYER_0_UNITS_16 16 #define NUM_LOGITS_16 1 -static const float full_pixel_motion_search_based_split_layer_0_kernel_16[] = { +static const float av1_simple_motion_search_based_split_layer_0_kernel_16[] = { -0.611497f, -0.0422086f, -0.555957f, -0.632451f, -0.144179f, -0.152722f, -0.330265f, -0.419866f, 0.287343f, 0.385295f, -0.424486f, 0.424281f, 2.27442f, -2.47933f, 5.24731f, 4.33827f, 4.73215f, 3.41909f, @@ -2793,23 +2662,23 @@ static const float full_pixel_motion_search_based_split_layer_0_kernel_16[] = { 0.0333619f, -0.377782f, 0.160767f, -0.128169f, -0.484818f, -0.311973f }; -static const float full_pixel_motion_search_based_split_logits_kernel_16[] = { +static const float av1_simple_motion_search_based_split_logits_kernel_16[] = { -0.132207f, 0.15176f, -0.680086f, 0.605921f, -0.43294f, 0.485811f, -0.306286f, 0.551368f, 0.413904f, 0.548748f, -0.437391f, 0.560778f, -0.00685266f, -0.558657f, 0.122127f, 0.260165f }; -static const float full_pixel_motion_search_based_split_layer_0_bias_16[] = { +static const float av1_simple_motion_search_based_split_layer_0_bias_16[] = { -0.200928f, -0.074132f, 8.69963f, -9.00807f, 9.08983f, -6.83586f, -3.89329f, 10.4881f, -0.0670618f, 0.0f, 9.21614f, 8.41773f, -0.145851f, 0.0f, -1.43038f, -0.0460311f }; -static const float full_pixel_motion_search_based_split_logits_bias_16[] = { +static const float av1_simple_motion_search_based_split_logits_bias_16[] = { -4.19885f }; -static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_16 = { +static const NN_CONFIG av1_simple_motion_search_based_split_nn_config_16 = { NUM_FEATURES_16, NUM_LOGITS_16, NUM_HIDDEN_LAYERS_16, @@ -2817,12 +2686,12 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_16 = { NUM_LAYER_0_UNITS_16, }, { - full_pixel_motion_search_based_split_layer_0_kernel_16, - full_pixel_motion_search_based_split_logits_kernel_16, + av1_simple_motion_search_based_split_layer_0_kernel_16, + av1_simple_motion_search_based_split_logits_kernel_16, }, { - full_pixel_motion_search_based_split_layer_0_bias_16, - full_pixel_motion_search_based_split_logits_bias_16, + av1_simple_motion_search_based_split_layer_0_bias_16, + av1_simple_motion_search_based_split_logits_bias_16, }, }; @@ -2838,7 +2707,7 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_16 = { #define NUM_LAYER_0_UNITS_8 16 #define NUM_LOGITS_8 1 -static const float full_pixel_motion_search_based_split_layer_0_kernel_8[] = { +static const float av1_simple_motion_search_based_split_layer_0_kernel_8[] = { 0.0370236f, -0.580211f, 2.0134f, 1.69637f, 2.43181f, -0.521648f, -0.00375187f, 0.122712f, -4.74411f, 7.36187f, 5.42574f, -5.53557f, 0.0993344f, -0.358843f, 0.0765453f, -0.615987f, -0.754633f, -0.175846f, @@ -2857,23 +2726,23 @@ static const float full_pixel_motion_search_based_split_layer_0_kernel_8[] = { 0.616966f, -0.451472f, -0.319365f, 0.00807278f, -0.303261f, -0.351679f }; -static const float full_pixel_motion_search_based_split_logits_kernel_8[] = { +static const float av1_simple_motion_search_based_split_logits_kernel_8[] = { -0.625847f, 0.381323f, 0.342475f, 0.526161f, -0.665965f, -0.515317f, -0.406218f, 0.568007f, 0.479397f, -0.426116f, 0.615638f, 0.338572f, 0.185583f, 0.308031f, 0.260748f, 0.531619f }; -static const float full_pixel_motion_search_based_split_layer_0_bias_8[] = { +static const float av1_simple_motion_search_based_split_layer_0_bias_8[] = { 4.73775f, -1.12658f, -0.258038f, -6.06696f, 1.79131f, 2.49609f, 4.28388f, 0.0f, -4.63598f, 3.06034f, 5.31994f, -0.152142f, 0.514738f, -1.30098f, 3.00296f, -3.83481f }; -static const float full_pixel_motion_search_based_split_logits_bias_8[] = { +static const float av1_simple_motion_search_based_split_logits_bias_8[] = { -3.44508f }; -static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_8 = { +static const NN_CONFIG av1_simple_motion_search_based_split_nn_config_8 = { NUM_FEATURES_8, NUM_LOGITS_8, NUM_HIDDEN_LAYERS_8, @@ -2881,12 +2750,12 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_8 = { NUM_LAYER_0_UNITS_8, }, { - full_pixel_motion_search_based_split_layer_0_kernel_8, - full_pixel_motion_search_based_split_logits_kernel_8, + av1_simple_motion_search_based_split_layer_0_kernel_8, + av1_simple_motion_search_based_split_logits_kernel_8, }, { - full_pixel_motion_search_based_split_layer_0_bias_8, - full_pixel_motion_search_based_split_logits_bias_8, + av1_simple_motion_search_based_split_layer_0_bias_8, + av1_simple_motion_search_based_split_logits_bias_8, }, }; @@ -2896,226 +2765,199 @@ static const NN_CONFIG full_pixel_motion_search_based_split_nn_config_8 = { // Thresholds for doing a single type of partition // TODO(chiyotsai@google.com): Set the thresholds for PARTITION_SPLIT. -static const float simple_motion_search_prune_part_only_thresh_128[10] = { +static const float av1_simple_motion_search_prune_part_only_thresh_128[10] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; -static const float simple_motion_search_prune_part_only_thresh_64[10] = { + +static const float av1_simple_motion_search_prune_part_only_thresh_64[10] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; -static const float simple_motion_search_prune_part_only_thresh_32[10] = { + +static const float av1_simple_motion_search_prune_part_only_thresh_32[10] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; -static const float simple_motion_search_prune_part_only_thresh_16[10] = { + +static const float av1_simple_motion_search_prune_part_only_thresh_16[10] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; -static const float simple_motion_search_prune_part_only_thresh_8[10] = { + +static const float av1_simple_motion_search_prune_part_only_thresh_8[10] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; // Thresholds for pruning a partition type -// TODO(chiyotsai@google.com): Retune the thresholds for rectangular partition. -static const float simple_motion_search_prune_part_prune_thresh_128[10] = { - 0.0f, 0.0110f, 0.0110f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f +static const float av1_simple_motion_search_prune_part_prune_thresh_128[10] = { + 0.0f, 0.0288721601835f, 0.0288721601835f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f }; -static const float simple_motion_search_prune_part_prune_thresh_64[10] = { - 0.0f, 0.0110f, 0.0110f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + +static const float av1_simple_motion_search_prune_part_prune_thresh_64[10] = { + 0.0f, 0.0281573780991f, 0.0281573780991f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f }; -static const float simple_motion_search_prune_part_prune_thresh_32[10] = { - 0.0f, 0.0110f, 0.0110f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + +static const float av1_simple_motion_search_prune_part_prune_thresh_32[10] = { + 0.0f, 0.0225501403434f, 0.0225501403434f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f }; -static const float simple_motion_search_prune_part_prune_thresh_16[10] = { - 0.0f, 0.0110f, 0.0110f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + +static const float av1_simple_motion_search_prune_part_prune_thresh_16[10] = { + 0.0f, + 0.000961189195907f, + 0.000961189195907f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f }; -static const float simple_motion_search_prune_part_prune_thresh_8[10] = { + +static const float av1_simple_motion_search_prune_part_prune_thresh_8[10] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; // Mean and std -static const float simple_motion_search_prune_part_mean_128[19] = { - 11.561261f, 11.626691f, 10.820066f, 10.880652f, 11.193911f, - 11.269741f, 10.509796f, 10.584754f, 12.659430f, 12.724323f, - 12.254200f, 12.326454f, 12.632568f, 12.694887f, 11.814313f, - 11.872458f, 13.690346f, 13.753730f, 5.165726f, -}; -static const float simple_motion_search_prune_part_std_128[19] = { - 2.434728f, 2.429037f, 3.701918f, 3.709713f, 3.288111f, 3.286657f, 4.174337f, - 4.185339f, 2.531916f, 2.540137f, 3.488878f, 3.496263f, 2.459336f, 2.460739f, - 3.919058f, 3.930766f, 2.511685f, 2.524923f, 2.257989f, -}; -static const float simple_motion_search_prune_part_mean_64[19] = { - 10.073195f, 10.158249f, 9.627341f, 9.708094f, 9.002025f, - 9.076430f, 8.597153f, 8.668316f, 11.021699f, 11.097507f, - 9.852887f, 9.919513f, 11.007151f, 11.085718f, 10.525035f, - 10.599575f, 11.936800f, 12.007580f, 4.860905f, -}; -static const float simple_motion_search_prune_part_std_64[19] = { - 2.272113f, 2.256767f, 3.023892f, 3.027094f, 3.794186f, 3.808349f, 4.143885f, - 4.164291f, 2.262401f, 2.249636f, 4.039632f, 4.053496f, 2.234799f, 2.219867f, - 3.136350f, 3.139975f, 2.199973f, 2.187191f, 2.185985f, -}; -static const float simple_motion_search_prune_part_mean_32[19] = { - 8.499073f, 8.600074f, 8.508158f, 8.611221f, 8.498978f, 8.599821f, 8.506126f, - 8.609448f, 9.481358f, 9.569901f, 9.481697f, 9.569918f, 9.469805f, 9.557789f, - 9.483047f, 9.572816f, 10.416696f, 10.496502f, 4.413157f, -}; -static const float simple_motion_search_prune_part_std_32[19] = { - 2.129560f, 2.117602f, 2.115962f, 2.104043f, 2.136564f, 2.125870f, 2.125247f, - 2.114250f, 2.146261f, 2.134374f, 2.160289f, 2.149360f, 2.116179f, 2.103744f, - 2.099453f, 2.087138f, 2.115011f, 2.101419f, 2.024279f, -}; -static const float simple_motion_search_prune_part_mean_16[19] = { - 6.990048f, 7.116367f, 6.883459f, 7.007796f, 6.993151f, 7.119445f, 6.886147f, - 7.010345f, 7.994230f, 8.099907f, 7.998478f, 8.104088f, 7.988468f, 8.092865f, - 7.868373f, 7.971079f, 8.946122f, 9.037547f, 3.976610f, -}; -static const float simple_motion_search_prune_part_std_16[19] = { - 1.963746f, 1.954729f, 2.127820f, 2.126451f, 1.963392f, 1.955016f, 2.126736f, - 2.126004f, 1.991209f, 1.981070f, 1.992683f, 1.983143f, 1.986913f, 1.977408f, - 2.200119f, 2.197786f, 1.997332f, 1.986091f, 1.829684f, -}; -static const float simple_motion_search_prune_part_mean_8[19] = { - 5.362649f, 5.561670f, 5.362880f, 5.564151f, 5.365307f, 5.565139f, 5.365830f, - 5.567452f, 6.453082f, 6.598073f, 6.458814f, 6.604363f, 6.454421f, 6.599441f, - 6.458431f, 6.604804f, 7.469143f, 7.585015f, 3.625800f, -}; -static const float simple_motion_search_prune_part_std_8[19] = { - 1.846273f, 1.835266f, 1.846272f, 1.834365f, 1.836967f, 1.826428f, 1.837247f, - 1.825985f, 1.886601f, 1.874138f, 1.874622f, 1.862656f, 1.877218f, 1.865398f, - 1.874494f, 1.862057f, 1.896421f, 1.883210f, 1.670200f, +static const float av1_simple_motion_search_prune_part_mean_128[25] = { + 13.292176f, 13.231236f, 11.098058f, 11.049944f, 10.481336f, + 10.431587f, 10.789337f, 10.732787f, 10.233817f, 10.173738f, + 12.214045f, 12.157505f, 11.863353f, 11.802220f, 12.204053f, + 12.152315f, 11.517566f, 11.465651f, 5.383040f, 0.757934f, + 4.012611f, 4.052191f, 0.853365f, 3.954503f, 3.944135f, +}; + +static const float av1_simple_motion_search_prune_part_std_128[25] = { + 2.589217f, 2.559396f, 2.268402f, 2.282274f, 3.341234f, 3.341994f, 3.033007f, + 3.041550f, 3.786247f, 3.784053f, 2.523459f, 2.511275f, 3.349364f, 3.340481f, + 2.390149f, 2.384226f, 3.599467f, 3.587460f, 2.319911f, 0.428335f, 1.241087f, + 1.208679f, 0.353742f, 1.228122f, 1.211777f, +}; + +static const float av1_simple_motion_search_prune_part_mean_64[25] = { + 11.439831f, 11.382639f, 9.647134f, 9.578121f, 9.146770f, + 9.084122f, 8.559063f, 8.499496f, 8.095865f, 8.041795f, + 10.547537f, 10.486240f, 9.362147f, 9.308391f, 10.548071f, + 10.484358f, 10.002225f, 9.944480f, 4.964504f, 0.897164f, + 3.306144f, 3.351039f, 0.928582f, 3.319739f, 3.287726f, +}; + +static const float av1_simple_motion_search_prune_part_std_64[25] = { + 2.033404f, 2.050657f, 2.064671f, 2.081519f, 2.916312f, 2.914649f, 3.628949f, + 3.618760f, 4.011421f, 3.996068f, 2.087127f, 2.103106f, 3.885277f, 3.876166f, + 2.035599f, 2.052976f, 3.052501f, 3.050985f, 2.232998f, 0.303745f, 1.111161f, + 1.081292f, 0.257521f, 1.112510f, 1.089404f, +}; + +static const float av1_simple_motion_search_prune_part_mean_32[25] = { + 9.862349f, 9.793658f, 8.043962f, 7.954083f, 8.058867f, 7.966165f, 8.046844f, + 7.956817f, 8.061414f, 7.967906f, 8.966450f, 8.890165f, 8.968315f, 8.891513f, + 8.953573f, 8.877070f, 8.974275f, 8.895363f, 4.387239f, 0.954143f, 2.701000f, + 2.751266f, 0.963302f, 2.716584f, 2.709725f, +}; + +static const float av1_simple_motion_search_prune_part_std_32[25] = { + 1.971555f, 1.985517f, 1.935986f, 1.944743f, 1.924122f, 1.932169f, 1.943151f, + 1.950612f, 1.931156f, 1.938242f, 1.987803f, 1.997670f, 2.000859f, 2.009913f, + 1.938270f, 1.949277f, 1.922999f, 1.933145f, 1.991504f, 0.209175f, 0.973824f, + 0.952221f, 0.188018f, 0.985295f, 0.946228f, +}; + +static const float av1_simple_motion_search_prune_part_mean_16[25] = { + 8.391692f, 8.303431f, 6.590342f, 6.459725f, 6.460719f, 6.333274f, 6.592615f, + 6.461661f, 6.464787f, 6.337191f, 7.499753f, 7.395166f, 7.503220f, 7.398344f, + 7.498312f, 7.395039f, 7.353743f, 7.253139f, 3.874267f, 0.979701f, 2.087404f, + 2.131698f, 0.981005f, 2.110868f, 2.106539f, +}; + +static const float av1_simple_motion_search_prune_part_std_16[25] = { + 1.865867f, 1.870012f, 1.773885f, 1.770447f, 1.972922f, 1.961361f, 1.777224f, + 1.772864f, 1.974519f, 1.962281f, 1.831632f, 1.831837f, 1.837595f, 1.837008f, + 1.822791f, 1.822053f, 2.074991f, 2.067200f, 1.676261f, 0.141022f, 0.840297f, + 0.829935f, 0.136507f, 0.828972f, 0.808563f, +}; + +static const float av1_simple_motion_search_prune_part_mean_8[25] = { + 6.997798f, 6.867032f, 5.134819f, 4.883330f, 5.134804f, 4.879707f, 5.140518f, + 4.886751f, 5.142186f, 4.885262f, 6.069946f, 5.896944f, 6.080442f, 5.906130f, + 6.077539f, 5.905929f, 6.083087f, 5.909298f, 3.552709f, 0.990654f, 1.497349f, + 1.531762f, 0.989606f, 1.496581f, 1.484139f, +}; + +static const float av1_simple_motion_search_prune_part_std_8[25] = { + 1.727562f, 1.725050f, 1.633396f, 1.618773f, 1.633586f, 1.620657f, 1.620798f, + 1.604892f, 1.621570f, 1.607439f, 1.691024f, 1.684225f, 1.676065f, 1.668442f, + 1.680016f, 1.672452f, 1.677775f, 1.671586f, 1.451902f, 0.096223f, 0.751190f, + 0.754040f, 0.101419f, 0.738239f, 0.729455f, }; -// BLOCK_128X128 #define NUM_HIDDEN_LAYERS_128 1 -#define NUM_FEATURES_128 19 -#define NUM_LAYER_0_UNITS_128 24 +#define NUM_FEATURES_128 25 +#define NUM_LAYER_0_UNITS_128 8 #define NUM_LOGITS_128 4 -static const float simple_motion_search_prune_part_logits_kernel_128[] = { - -0.12815f, -1.2107f, 0.525183f, 0.379155f, -2.04966f, -0.212818f, - -0.0609484f, -0.119338f, 1.07054f, -0.0304129f, 0.563817f, -0.0204729f, - 0.757013f, 0.464791f, 0.191185f, 0.183903f, -2.71738f, 1.41455f, - -0.449089f, -0.0344047f, 0.349133f, -0.945292f, 0.63729f, -0.973444f, - -0.203447f, -19.7875f, -12.7536f, -0.260806f, 0.934733f, -3.17648f, - -1.11806f, -4.63145f, -16.0947f, -24.203f, -2.94649f, -8.34109f, - -0.720804f, -5.16623f, -0.443715f, 0.510014f, -4.2846f, -11.2272f, - 0.187633f, -10.0189f, -0.915574f, -0.235434f, -2.57912f, 0.151642f, - -0.180428f, -0.110439f, 0.349015f, -1.83906f, -3.38461f, -0.309185f, - -9.3706f, -5.54824f, 0.45334f, -8.48801f, 0.392325f, -4.19948f, - -0.535814f, -4.92133f, 0.0159878f, 0.275078f, -2.65358f, 1.32524f, - -0.761795f, -14.782f, -4.15338f, -0.177581f, -0.158376f, -0.0832793f, - 0.226712f, -0.349409f, 0.0529463f, -0.412873f, -0.241807f, 0.19054f, - 0.79237f, 0.218937f, -1.60466f, 0.845653f, -0.287058f, 0.766271f, - -0.455829f, 0.00261991f, 0.506805f, -0.0593004f, 2.25348f, -2.29282f, - 0.0491916f, 0.38261f, -0.281848f, -0.17802f, -0.472124f, 0.204326f +static const float av1_simple_motion_search_prune_part_logits_kernel_128[] = { + -0.129103f, 0.457758f, -0.489986f, 0.65462f, -0.184312f, 3.81202f, + -0.444407f, -0.64198f, -0.575008f, 0.0311711f, 0.525243f, -20.892f, + 1.08811f, -65.0976f, -12.3973f, -1.38278f, -0.264233f, 0.241636f, + -10.6925f, -0.725414f, -18.8987f, -40.2284f, -16.08f, 0.995331f, + 1.47614f, -0.964864f, 0.405506f, 0.140449f, 0.459534f, -1.9093f, + 0.398452f, 0.696949f }; -static const float simple_motion_search_prune_part_layer_0_kernel_128[] = { - 0.485797f, -0.326149f, 0.238042f, -1.41255f, -0.00899515f, - -0.715324f, 0.623049f, 0.502229f, 0.54064f, -0.0667834f, - 0.0591777f, -0.435869f, 0.221466f, -0.222184f, 0.696493f, - -0.514433f, -0.771882f, -0.080914f, -1.58162f, -0.214871f, - -0.0141856f, -0.566004f, -1.01071f, -0.0400122f, -0.212581f, - 0.144009f, 0.156065f, 0.419812f, 0.351579f, -0.0363798f, - 0.272286f, 0.177348f, 0.643484f, -0.686943f, -1.5021f, - -0.283203f, -0.317958f, 0.834615f, 1.18195f, 0.704402f, - 0.723567f, 0.0765064f, 0.0998969f, 0.358114f, -0.471958f, - -0.33568f, -0.0455057f, 0.0659417f, 0.717502f, 1.40203f, - -1.78214f, -1.00743f, -0.217992f, -0.244456f, -0.681988f, - 0.199185f, 1.27797f, 0.744351f, 0.853728f, 0.976386f, - 1.5212f, 0.246886f, 0.458125f, -0.278508f, -0.601164f, - -0.874409f, -0.0882617f, -0.93093f, -0.0279819f, 0.289613f, - -0.795015f, 1.2224f, 0.464495f, -0.996107f, -1.05131f, - 0.780663f, 1.70779f, -0.122481f, 2.64976f, 0.284897f, - -0.129159f, -0.0472128f, 0.190105f, 0.549306f, -0.829239f, - -2.87392f, 0.0735607f, -1.00692f, -0.0171315f, 0.217386f, - 0.715055f, 1.2976f, -0.387801f, -0.301424f, -0.265159f, - 0.381381f, -0.637641f, 0.424966f, 0.317794f, 1.99832f, - 0.604094f, 0.444838f, 0.354898f, -0.2603f, -0.625206f, - 1.37372f, 0.474128f, 1.47492f, -0.318267f, -0.32122f, - -1.29434f, 0.426303f, -0.604944f, -2.33438f, -1.33476f, - -2.13254f, 2.28472f, 0.844804f, 0.366394f, 0.148218f, - -0.0996413f, -0.665787f, 1.30951f, 0.447868f, -0.160892f, - 0.336539f, -0.461251f, -0.940939f, 1.9886f, 0.774578f, - -0.0274317f, -0.288034f, -0.188082f, 0.296018f, -0.171846f, - 0.245583f, 0.39913f, -0.0544446f, 0.823534f, 0.215969f, - -0.393239f, -0.208693f, -0.336752f, 0.258191f, 1.03315f, - -0.0356378f, -0.35999f, 0.48529f, 1.09123f, -0.243654f, - 0.131594f, -2.5832f, 1.26485f, -0.700618f, 0.466223f, - -0.525984f, 2.19872f, 0.685663f, 1.40228f, 1.10528f, - 0.0451285f, -0.39981f, -0.644025f, -1.31137f, 0.836056f, - -0.884238f, 0.394441f, -0.16017f, -1.45246f, -1.24252f, - 0.195623f, 0.716485f, -0.0522381f, 0.271321f, 0.560211f, - 0.685537f, -0.117774f, -0.227596f, 0.346762f, -0.402137f, - 0.00528979f, 0.756388f, 0.181091f, -0.513235f, -0.354307f, - 1.04355f, -0.114563f, 0.457349f, -0.525175f, -1.306f, - -1.57685f, -1.69919f, 0.393799f, 1.35822f, -0.496799f, - 0.102504f, -0.0950497f, 0.518029f, 0.211844f, 0.385925f, - 0.366614f, 0.52377f, -0.22419f, -0.209355f, 0.343361f, - 0.0535484f, 0.320409f, 0.467987f, -0.00542184f, -1.02011f, - 0.488822f, -0.248647f, 0.113298f, -0.665206f, 0.374419f, - 0.731859f, 1.20004f, -0.000319085f, -0.000491633f, -0.260543f, - 0.804927f, -0.410925f, 0.960751f, 0.281493f, 0.607288f, - -0.681745f, -0.0925707f, -2.06876f, -0.52926f, 0.864695f, - -0.712922f, 0.706643f, -0.651177f, -0.231887f, -0.318515f, - 0.0635488f, -0.183294f, -0.589271f, 0.288583f, 0.38702f, - 0.582912f, 0.225519f, 1.23027f, 0.108471f, 1.3328f, - 0.689896f, -2.21988f, -0.337789f, -0.762238f, 1.79149f, - 0.840519f, 0.825442f, 0.460811f, 0.434437f, 2.13268f, - -0.341805f, -0.139746f, -1.66773f, -0.583511f, -0.238547f, - 0.156871f, 0.719404f, 1.05882f, -0.173445f, -0.867368f, - 0.170469f, 1.57755f, 1.36095f, -0.418987f, -0.396689f, - 0.289496f, -0.292606f, 0.688943f, 0.176553f, 0.853828f, - 1.19608f, -0.557087f, -0.58118f, 1.12805f, 0.232023f, - -0.167864f, -0.222265f, -0.719284f, -0.802184f, -2.85383f, - -1.01816f, -1.344f, -0.154875f, 0.308999f, -0.62822f, - 0.389045f, -0.498046f, -0.0646747f, 0.056343f, 0.188288f, - 0.493475f, 0.241337f, 0.122423f, -0.506522f, 0.0492923f, - 0.0642163f, -0.508636f, 0.0328815f, 0.78567f, 0.224673f, - 0.627972f, 0.759423f, 1.16089f, 1.28274f, 1.19646f, - 1.63401f, 1.56657f, -0.131442f, -0.423053f, -0.599536f, - -1.20933f, 0.0438751f, -0.538444f, -0.749136f, -0.769951f, - -1.06683f, -1.66474f, 0.136208f, 1.35745f, -0.960854f, - 2.32612f, 0.349384f, 1.04506f, -0.888194f, 1.28114f, - 0.579831f, 0.53927f, -1.07214f, 0.456708f, -0.884062f, - 0.789767f, -0.776746f, -0.0143946f, -0.930974f, -0.632568f, - -1.487f, 0.0284456f, -0.865849f, -1.51263f, 0.117335f, - -0.671304f, -0.367558f, -0.650224f, 1.09562f, 0.246097f, - 0.461775f, -0.722606f, 0.0886829f, -0.490978f, 1.92718f, - 0.864959f, 0.0705385f, -0.543902f, 1.4704f, -0.643494f, - 0.194486f, 0.890657f, 0.901154f, -0.458931f, 0.209679f, - 0.303869f, -0.167078f, 1.60197f, 1.05005f, -0.499959f, - 0.930484f, -0.555236f, -0.778482f, -0.772935f, -0.590988f, - -0.122397f, -0.346605f, 0.100747f, -0.237732f, -0.180927f, - 0.136491f, -0.230076f, 1.52049f, 1.70212f, 0.415758f, - -0.811552f, 0.570249f, 1.73167f, 0.808393f, -1.28608f, - 0.518307f, 0.601205f, 0.258751f, -0.498631f, -0.790802f, - -0.465072f, -0.507542f, 0.312956f, -0.485421f, -0.0525576f, - 0.24136f, -0.201595f, -0.721587f, 0.190955f, -0.123108f, - -0.263243f, -0.36142f, -0.105093f, 0.0651603f, 0.240065f, - 0.241104f, -0.238277f, -1.11714f, 1.50723f, 0.443715f, - 1.83051f, 1.29719f, -0.0367089f, 1.57883f, 1.96011f, - 0.0373268f, 0.480469f, 0.497726f, 1.47078f, -0.359254f, - 0.120578f, -0.651964f, -0.537215f, -1.20527f, -0.374681f, - -0.443443f, -0.39421f, 0.688228f, 0.0989643f, -1.28785f, - -1.24392f, -0.165236f, 1.1812f, -0.76329f, 1.44085f, - -0.540544f, 0.0958765f, -0.31224f, 0.471211f, -0.997358f, - 1.16174f, -0.948466f, 0.660749f, -0.574517f, 1.42706f, - -0.477758f, 0.509914f, -0.930534f, 0.722869f, -0.955477f, - -0.383073f +static const float av1_simple_motion_search_prune_part_layer_0_bias_128[] = { + 1.22789f, -1.34527f, 0.759048f, 0.315086f, + 1.0834f, -1.58019f, -0.465158f, 1.20716f }; -static const float simple_motion_search_prune_part_logits_bias_128[] = { - 0.814703f, -1.18485f, -1.49788f, -0.0054509f +static const float av1_simple_motion_search_prune_part_layer_0_kernel_128[] = { + -0.668677f, 0.58694f, -0.417094f, 0.754735f, -0.7859f, + 0.377479f, -0.0415929f, -0.0140585f, -0.730001f, 0.747528f, + -0.135247f, 0.406505f, -0.234184f, 0.956362f, -0.637555f, + 0.791884f, 0.0303722f, 1.04424f, -0.727859f, -0.274321f, + -0.122986f, 0.066312f, -0.00559175f, -0.239643f, -0.0188767f, + -0.102787f, -0.262967f, 0.071882f, -0.283398f, 0.111607f, + -0.425826f, 0.02699f, 0.108873f, -0.180558f, -0.0794057f, + 0.29665f, -0.0252969f, -0.0266213f, -0.277462f, -0.361973f, + 0.512552f, 0.395011f, -0.225876f, 0.301924f, 0.136954f, + 0.507259f, 1.23425f, 0.0137135f, 0.662572f, 0.591583f, + 0.101564f, 0.416805f, -0.645081f, -0.179086f, -0.36747f, + -0.332213f, 0.095177f, 0.220739f, -0.153256f, 0.706155f, + 0.161701f, 0.696815f, -1.21531f, -0.115059f, 0.486764f, + -0.396093f, 0.784883f, 0.535357f, -0.278021f, 0.143496f, + -0.44931f, -0.144543f, 0.319326f, 0.0190167f, -0.206295f, + 0.373995f, -0.247897f, -0.608095f, -0.41796f, -0.137129f, + -0.709562f, 0.678273f, 0.537607f, 0.557474f, 0.453308f, + 0.21405f, -0.0466495f, 0.519139f, -0.168832f, 0.902911f, + 0.681131f, -0.139876f, -0.2052f, -0.393271f, 0.262222f, + -0.246246f, -0.213993f, 0.646619f, 0.0496181f, -0.00354157f, + 0.822927f, 0.0939522f, 0.180738f, 0.118355f, 0.120456f, + -0.0472214f, -0.144958f, 0.173405f, -0.886644f, -0.0949769f, + -0.813518f, -0.3947f, -0.128021f, 0.356196f, 0.469169f, + -0.413702f, 1.04242f, 0.428853f, -0.387293f, 0.0850877f, + 0.279409f, -0.142276f, 0.0579376f, 0.211112f, 0.0703013f, + -1.9274f, -0.729147f, 0.534193f, 0.773586f, 0.922864f, + 0.642881f, 1.15127f, 0.621032f, 0.933942f, 1.01837f, + -0.660282f, -0.40059f, -1.11279f, -0.77088f, -0.43349f, + 0.202361f, -0.0840912f, 0.0935707f, 0.056333f, -0.0779369f, + 0.0173447f, -0.0104756f, 0.0115005f, -0.0195593f, 0.03592f, + -0.343454f, -0.618048f, 0.258172f, -0.412322f, -0.0463746f, + -0.0413654f, -0.0400194f, 0.615981f, -0.452094f, 0.644555f, + 0.0822476f, -0.359791f, -0.0904274f, 0.209427f, 0.0116338f, + -0.190978f, 0.890233f, 0.737769f, -1.66663f, -0.392605f, + 0.0785728f, -0.224553f, -0.128258f, -0.227227f, -0.0777773f, + 0.685976f, 0.347042f, -0.555325f, -0.249221f, 0.0919837f, + -0.0660016f, -0.272316f, 0.0390632f, -0.619624f, -0.0565801f, + 0.585026f, 0.597375f, 0.54114f, 0.593389f, 0.604391f, + 0.0820294f, -0.85339f, -1.40741f, -0.391675f, 0.0579205f, + -0.197626f, 0.130044f, -0.234488f, -0.0373991f, -0.0717973f }; -static const float simple_motion_search_prune_part_layer_0_bias_128[] = { - -0.283185f, -2.5867f, -2.07531f, -2.31513f, -1.85869f, -0.310685f, - -0.802324f, 0.056964f, -1.43881f, 2.84016f, -1.15494f, -2.30652f, - 0.015622f, 0.303776f, 0.774322f, -1.25979f, -2.37144f, -1.35687f, - 0.743607f, 0.768569f, -1.09908f, -0.470101f, -0.615497f, 1.04214f +static const float av1_simple_motion_search_prune_part_logits_bias_128[] = { + 1.58571f, -4.6314f, -2.00273f, 0.543699f }; -static const NN_CONFIG simple_motion_search_prune_part_nn_config_128 = { +static const NN_CONFIG av1_simple_motion_search_prune_part_nn_config_128 = { NUM_FEATURES_128, NUM_LOGITS_128, NUM_HIDDEN_LAYERS_128, @@ -3123,12 +2965,12 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_128 = { NUM_LAYER_0_UNITS_128, }, { - simple_motion_search_prune_part_layer_0_kernel_128, - simple_motion_search_prune_part_logits_kernel_128, + av1_simple_motion_search_prune_part_layer_0_kernel_128, + av1_simple_motion_search_prune_part_logits_kernel_128, }, { - simple_motion_search_prune_part_layer_0_bias_128, - simple_motion_search_prune_part_logits_bias_128, + av1_simple_motion_search_prune_part_layer_0_bias_128, + av1_simple_motion_search_prune_part_logits_bias_128, }, }; @@ -3137,163 +2979,246 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_128 = { #undef NUM_LAYER_0_UNITS_128 #undef NUM_LOGITS_128 -// BLOCK_64X64 #define NUM_HIDDEN_LAYERS_64 1 -#define NUM_FEATURES_64 19 -#define NUM_LAYER_0_UNITS_64 24 +#define NUM_FEATURES_64 25 +#define NUM_LAYER_0_UNITS_64 32 #define NUM_LOGITS_64 10 -static const float simple_motion_search_prune_part_logits_kernel_64[] = { - -2.71432f, 0.853994f, 0.740156f, -0.30982f, -0.448512f, 0.0984177f, - -0.664821f, -0.150188f, 0.104798f, 1.27746f, 0.217043f, -0.553914f, - -0.985639f, 1.99904f, -0.994877f, 0.0697683f, 0.64856f, -0.412276f, - -0.740292f, 0.93851f, 0.647461f, 0.874707f, -1.06881f, 0.704589f, - 0.641148f, -0.23997f, -0.0955951f, 0.249869f, -0.240726f, 0.420737f, - -0.558423f, -0.863005f, 0.981276f, -0.520796f, 0.206416f, -0.0512005f, - -0.76665f, -0.341038f, -0.727661f, 0.348269f, -0.0786858f, -0.370214f, - -0.292226f, -0.106107f, 0.262638f, 1.0065f, 0.558744f, -0.0492801f, - -1.22877f, 0.225909f, 0.485238f, -0.009513f, -0.299224f, -0.405938f, - -0.379131f, 0.0190173f, -0.66387f, 0.846164f, 0.298606f, -0.811507f, - -0.0853147f, -0.146277f, 0.0860954f, 0.151524f, 0.239613f, -0.0141985f, - 0.684708f, -0.0732401f, -0.709585f, -1.86211f, -0.622393f, -0.503456f, - 0.482376f, -0.10075f, -0.449184f, 0.999368f, 0.442391f, -0.60335f, - 0.631041f, 0.377315f, -0.141438f, -0.395021f, -0.750439f, 0.79456f, - 0.29555f, -1.51727f, 0.964882f, -0.256708f, -0.182677f, 0.727967f, - 0.411337f, -0.252901f, -0.546165f, -0.620733f, 0.948828f, 0.187498f, - -6.20879f, 0.1671f, -0.131667f, -0.0719152f, -0.101839f, -0.326827f, - 0.00418824f, -0.819253f, -0.168854f, -0.588437f, -0.192699f, 0.126879f, - -0.0287044f, -0.686708f, -0.445826f, -0.0993483f, -0.682881f, 0.0685043f, - -0.472371f, -0.399788f, 0.170985f, -0.164692f, -0.380181f, -0.268889f, - -3.16193f, -0.965943f, -0.178737f, -0.517274f, -0.102274f, -0.359742f, - 0.0117419f, -0.0690246f, 0.206539f, -1.29449f, 0.0976349f, -0.188444f, - 0.160939f, -0.387867f, -0.34513f, -0.221073f, -0.326615f, 0.0302811f, - 0.245349f, -0.381586f, 0.0414228f, -0.414076f, 0.0232891f, -0.118837f, - -2.81659f, -0.288328f, -0.0328096f, -0.61535f, -0.23593f, -1.16019f, - -0.0619081f, 0.0646133f, -0.313036f, -0.390373f, -0.0481636f, 0.0450287f, - 0.196415f, -0.717419f, -0.0707908f, -0.2078f, -0.459761f, 0.230835f, - -0.0703036f, -0.112402f, -0.170908f, 0.0485359f, -0.237293f, -0.989058f, - -2.05295f, 0.134268f, -0.173105f, -0.493955f, -0.28408f, -0.91465f, - -0.00206022f, -0.297255f, 0.161636f, -0.52414f, -0.324677f, -0.321039f, - 0.188412f, -0.333399f, -0.325067f, -0.024484f, 0.128572f, 0.20541f, - -0.0743476f, 0.0762302f, -0.0370672f, -1.53757f, -0.199054f, -0.318512f, - -3.41239f, -0.50942f, 0.100088f, 0.395587f, 0.00633016f, 0.851201f, - -0.0700995f, -0.685436f, 0.0817234f, -0.632139f, -0.41931f, 0.15613f, - -0.201166f, -0.0721472f, -0.239791f, 0.656797f, -0.501886f, -0.160969f, - -0.561536f, -0.491154f, -0.213447f, 0.21926f, -0.542261f, 0.594975f, - -1.75303f, 0.284615f, -0.0128245f, -0.0316972f, -0.300138f, -0.980628f, - -0.332859f, 0.19298f, -0.248332f, 0.445278f, -0.470188f, -0.483686f, - 0.361407f, -0.363551f, 0.175335f, -0.401025f, 0.494573f, 0.366983f, - 0.302351f, -0.368503f, -0.443071f, -0.562775f, -0.375816f, -0.657459f +static const float av1_simple_motion_search_prune_part_logits_kernel_64[] = { + 0.10424f, -0.346025f, 0.534547f, -0.385925f, 2.58341f, -0.256414f, + -0.232498f, 0.329823f, -0.0777376f, -0.590939f, 0.062657f, -0.628252f, + 0.0934588f, 2.04029f, -0.224448f, 0.371168f, -0.385348f, -0.589883f, + -3.73627f, -0.943144f, 0.346409f, -0.211215f, -0.351008f, 0.418807f, + 0.943663f, 0.173267f, 1.16585f, -0.0840888f, 0.227464f, 0.374412f, + 0.0422597f, -0.338868f, 0.222576f, 0.431713f, 1.12366f, 0.00753411f, + 0.248412f, -0.0902425f, 0.542455f, -0.665629f, -0.311245f, -0.205639f, + -0.447149f, -0.0502733f, -0.290186f, -0.794384f, 0.0940881f, -0.0686117f, + -0.0199961f, -0.587965f, 0.777096f, -0.083381f, -1.21282f, 0.652959f, + -1.18238f, 0.539991f, 0.352497f, -0.540076f, -0.26222f, -0.568556f, + 0.409102f, -0.131146f, -0.407161f, -0.188287f, -0.478657f, 0.000401932f, + -0.689324f, 0.351064f, -1.43704f, -0.315185f, -0.868726f, 0.376341f, + -0.0566277f, 0.364831f, 0.611298f, -0.495253f, -0.0193132f, 0.617978f, + 0.189586f, -0.236758f, -0.608246f, -0.149017f, -1.78303f, 0.143023f, + 0.698386f, -0.994086f, -0.673327f, 0.233868f, 0.360425f, 0.0294123f, + -0.248683f, -0.148392f, 0.0861829f, -0.190843f, -0.414906f, 0.607378f, + -0.756715f, -0.511713f, -0.321556f, 1.0078f, -1.18141f, 0.519751f, + 0.834629f, -0.359343f, 0.612262f, -0.0730553f, 0.262935f, 0.488276f, + 0.387071f, -1.44123f, 1.08269f, 0.554402f, -0.069f, 0.14113f, + 0.323817f, 0.824314f, -0.431417f, -0.349448f, 0.950728f, -0.587836f, + -0.83914f, -0.10844f, 0.26602f, 0.831933f, -0.271315f, 0.231563f, + 0.417049f, 0.190627f, -0.0940667f, 0.255363f, -0.0741022f, -0.0987662f, + -0.847522f, 0.00287554f, 0.0615741f, -0.0832218f, 0.0847148f, -0.392843f, + -0.938068f, -0.10621f, -0.260859f, -0.825175f, -0.401039f, 0.315213f, + -0.108269f, 0.288036f, -8.66166f, -0.970752f, -0.66678f, -0.593405f, + -0.518294f, -0.138722f, -0.454698f, -0.22969f, -0.553006f, -0.440111f, + 0.462661f, -0.536854f, 0.0108295f, -0.522888f, 0.00111157f, 0.229999f, + 0.0267768f, 0.176266f, -1.57043f, 0.0318106f, 0.257534f, -0.198583f, + 0.175564f, -0.251465f, -0.262441f, -1.65283f, -0.319603f, -0.875282f, + -0.301303f, 0.0170948f, -0.227075f, 0.0299545f, -4.98346f, 0.470046f, + -1.28051f, -0.213809f, -0.486585f, -0.906463f, -0.169984f, -0.333153f, + -0.376733f, 0.108016f, 0.486744f, -0.186936f, -0.429259f, 0.056501f, + -0.266545f, 0.265447f, -0.137718f, -0.490687f, -0.935668f, -0.16229f, + -0.696932f, 0.173157f, 0.434959f, -0.140595f, 0.345845f, -1.08013f, + -0.0205929f, -0.815874f, -0.179812f, 0.02767f, -0.141727f, 0.471936f, + -7.29453f, -1.04362f, -0.745482f, -0.28725f, -0.214997f, -0.0850651f, + -0.748471f, 0.161325f, -1.04387f, -0.705305f, 0.489427f, -0.765373f, + -0.301576f, 0.0742467f, -0.331282f, 0.0372328f, -0.90298f, -0.0608646f, + -2.18756f, 0.170384f, -0.258357f, 0.106287f, -0.161684f, -0.103799f, + -0.127774f, -0.156313f, 0.0705286f, -0.977908f, -0.281191f, -0.056757f, + -0.309474f, 0.050476f, -9.78198f, -2.42795f, -0.289626f, -1.07579f, + -0.439256f, -1.09948f, -0.564671f, 0.0913182f, -0.417216f, -1.19909f, + 0.287063f, 0.402315f, -0.17646f, 0.540488f, 0.00840239f, 0.397492f, + 0.702393f, -0.10566f, 0.655296f, -0.0443876f, 0.154918f, -0.760479f, + -0.0523153f, -0.366199f, -1.08212f, -0.398556f, -0.415203f, -1.10488f, + 0.208349f, 0.27079f, 0.101546f, -0.205752f, -13.7923f, -0.218637f, + -1.10077f, 0.355735f, -0.306196f, 0.627434f, -0.473101f, -0.308027f, + -1.12724f, 0.301597f, 0.660785f, 0.0576217f, -0.155925f, -0.56107f, + -0.223537f, 0.114299f, -0.53803f, -0.252674f, -2.66103f, -0.185245f, + -0.314673f, 0.403337f, 0.679821f, -0.69231f, 0.506264f, -0.999705f, + -0.549097f, 0.353745f, 0.188249f, 0.414484f, -0.615853f, 0.525681f, + -5.23065f, -3.05174f, 1.02074f, -0.965499f, -0.158947f, 0.0436088f, + -0.485824f, 0.0375094f, -1.39985f, -0.481392f, 0.485785f, -0.24874f, + -0.359633f, 0.668108f }; -static const float simple_motion_search_prune_part_layer_0_kernel_64[] = { - 0.615272f, -0.151592f, 0.346172f, -0.0656032f, 0.212875f, - 0.0798838f, -0.146093f, -0.230484f, -0.620322f, 0.0277852f, - -0.400931f, -0.777044f, -0.0871401f, -0.248128f, 0.471518f, - -0.34174f, -0.149884f, -0.0763207f, 0.900372f, 0.233323f, - -0.788699f, 0.28221f, 0.327214f, -0.244877f, -0.414568f, - 0.0472988f, 0.168193f, 0.64126f, 0.56686f, -0.318429f, - 0.530612f, -0.750709f, 0.0400333f, -0.023951f, -0.0218727f, - -0.0449836f, -0.0764245f, -0.070088f, -0.0427561f, -0.0873884f, - -0.216423f, 0.622787f, 0.0297492f, -0.233673f, 0.510639f, - 0.481654f, -0.234274f, 0.347734f, -0.480302f, 0.832741f, - 0.228223f, 0.247019f, -0.32416f, 0.352315f, -1.1491f, - 0.00806435f, -0.439654f, 0.151723f, -0.0719021f, 0.463499f, - 0.00134313f, 0.0553619f, -0.582163f, -0.215118f, -0.291413f, - 0.889738f, 0.284575f, 0.00450409f, -0.896799f, 0.0303598f, - 0.187935f, -0.160993f, 0.089854f, 0.0450689f, -0.548899f, - -0.10556f, 0.29384f, -0.154158f, 0.423591f, 0.322065f, - 0.244633f, -0.320866f, 0.739022f, -0.500495f, 0.595557f, - -0.62001f, 0.259688f, 0.114985f, -0.13888f, -0.0737616f, - 0.801863f, -0.0606944f, 0.238712f, -0.0636556f, 0.04317f, - 0.359843f, -0.273265f, 0.782092f, 0.341857f, 0.884373f, - 0.378388f, 0.632049f, 0.633597f, -0.32103f, -1.1014f, - -0.852525f, -0.867999f, 0.228625f, 0.444601f, 0.246595f, - 0.386288f, -0.341772f, -0.335849f, -0.482717f, 0.00928882f, - -0.262618f, 0.497003f, 0.579316f, 0.371681f, -0.440324f, - 0.115786f, -0.112295f, 0.07564f, -0.326419f, -0.195152f, - 0.315485f, -0.368989f, 0.281852f, 0.418865f, 0.807047f, - 0.293759f, -0.129749f, -1.26096f, -0.0526466f, -0.618876f, - 0.330563f, 0.26479f, 0.364751f, 0.68361f, 0.500237f, - -0.564011f, 0.158277f, -0.214105f, 0.50558f, 0.69422f, - -0.172224f, -0.280568f, 0.17241f, -0.500658f, -0.00418558f, - -0.420356f, 0.0453594f, 0.00471851f, -0.273979f, 0.355633f, - 0.515393f, 0.0699701f, -0.413576f, 0.487255f, -0.388845f, - -0.192441f, -0.353274f, -0.1773f, 0.256746f, -0.380197f, - 0.023061f, 0.431125f, 1.0368f, -0.0915799f, -0.268898f, - 0.0408016f, 0.593356f, 0.308486f, 0.508452f, -0.0623963f, - 0.307066f, 0.180916f, 0.326197f, 0.246641f, 0.270665f, - -0.145655f, -0.341277f, 0.0218018f, -0.326939f, -0.203528f, - -0.25496f, -0.772783f, -0.306114f, -0.79778f, 0.690016f, - -0.183109f, -0.076211f, -0.474873f, -0.0219729f, -0.152253f, - -0.0315833f, -0.134908f, -0.111871f, 0.0409385f, -0.282586f, - -0.101171f, 0.351942f, 0.30023f, 0.369243f, 0.0619639f, - -0.170842f, -0.235501f, -0.615927f, 0.883574f, 0.150949f, - -0.338489f, -0.213431f, -0.6075f, -0.107739f, -0.251963f, - 0.143906f, 0.254205f, -0.260084f, 0.224897f, 0.609902f, - 0.5606f, 0.795273f, 0.117204f, 0.345592f, 0.243912f, - 0.0626369f, -0.166448f, -0.886364f, -0.280833f, -0.0891074f, - 0.0372486f, -0.138729f, 0.120189f, 0.345857f, 0.176341f, - 0.481862f, -0.137464f, -0.208001f, 0.621677f, -0.121462f, - 0.00445475f, 0.159351f, 0.149918f, 0.198679f, -0.489814f, - -0.30931f, -0.39161f, 0.268615f, 0.323864f, 0.770061f, - 0.27962f, 0.536173f, 0.122727f, 0.571712f, 0.48351f, - -0.13558f, -0.426532f, -0.100426f, -0.209695f, 0.470483f, - -0.424789f, 0.0973791f, -0.296483f, -0.302057f, -0.918591f, - 0.16328f, 0.0335916f, 0.415762f, -0.235873f, -0.00934998f, - -0.0967718f, 0.616418f, 0.0931619f, -0.447975f, 0.156388f, - -0.40139f, 0.382807f, -0.578455f, 1.01437f, 0.37469f, - -0.986411f, -0.827175f, 0.0344976f, -0.00244486f, -0.142117f, - -0.344406f, -0.0124787f, -0.226427f, -0.301835f, -0.705097f, - 0.214542f, -0.0346878f, -0.255193f, 0.552685f, -0.104125f, - 0.77408f, 0.00984395f, 0.0476041f, -0.244548f, -0.35082f, - -0.487322f, 0.700091f, -0.138812f, -0.0110718f, -0.0400376f, - 0.254488f, -0.0867923f, -0.215463f, 1.03355f, 0.214947f, - 0.385536f, 0.140597f, -0.234973f, -0.0611124f, 1.0974f, - 0.463592f, -0.393788f, -0.428132f, -0.14664f, -0.156533f, - -0.113426f, -0.111081f, -0.0228256f, 0.354909f, -0.0232978f, - 0.177394f, 0.0503901f, -0.220314f, 0.170207f, 0.236719f, - 0.681525f, -0.245544f, -0.119278f, -0.258491f, -0.285309f, - 0.186384f, -0.119177f, -0.279398f, -0.097341f, -0.324634f, - -0.296797f, -1.3325f, 0.147225f, 0.0158408f, -0.0365257f, - -0.166737f, -0.159859f, -0.0765398f, 0.0973026f, 0.294529f, - -0.16425f, 0.241506f, 0.561487f, 0.799885f, -0.565667f, - -0.254387f, -0.360831f, -0.138432f, 0.406999f, 0.463259f, - -0.497314f, -0.00549591f, -0.0313973f, -0.386042f, -0.364537f, - -0.079987f, 0.148503f, 0.0532473f, -0.0196838f, 0.232687f, - 0.212998f, 0.2142f, 0.409001f, -0.104871f, -0.217793f, - 0.0161162f, -0.371663f, 0.887427f, 0.420187f, -0.649711f, - -0.398999f, 0.448972f, -0.116108f, 0.0444676f, -0.501289f, - -0.0410878f, 0.00447241f, -0.402102f, -0.0926268f, -0.254362f, - -0.395526f, 0.165273f, 0.339347f, 0.91932f, -0.280113f, - 0.320112f, -0.102728f, -0.131682f, -0.566621f, 0.386611f, - 0.146975f, 0.333248f, -0.179748f, 0.655328f, 0.222658f, - 0.349512f, -0.135588f, -0.22506f, -0.353001f, -0.400244f, - -0.815125f, 0.72407f, 0.281178f, -0.109426f, -0.0977383f, - -0.679406f, -0.401318f, 0.308941f, -0.594461f, 0.482289f, - -0.168467f, 0.76529f, -0.155056f, 0.0874018f, 0.266124f, - -0.0808725f, 0.078792f, -0.33271f, -1.0637f, -0.172125f, - 0.427025f, 0.332865f, 0.625523f, 0.264166f, -0.843882f, - -0.275777f, -0.657372f, 0.172814f, 0.0490389f, -0.561928f, - 0.0998399f, 0.106047f, 0.39061f, 0.422161f, 0.46369f, - -0.364271f, -0.326968f, -0.527243f, -0.618535f, -0.287804f, - -0.211365f, 0.349277f, 0.456535f, -0.0815191f, -0.156835f, - 0.57273f +static const float av1_simple_motion_search_prune_part_layer_0_bias_64[] = { + 0.0735592f, -0.045064f, -0.0114103f, 1.39246f, -0.683467f, 0.155765f, + -0.667652f, -0.202425f, -0.585433f, -0.146752f, -0.0812931f, 0.580642f, + 0.578542f, -0.831916f, 0.610063f, 0.0101856f, -0.235863f, 0.538141f, + -2.91334f, -1.71887f, 0.126616f, 0.582497f, -0.438879f, 0.221833f, + 0.850773f, -0.280886f, 0.443233f, -0.0964873f, -0.216161f, 0.34413f, + 0.656818f, 0.0169274f }; -static const float simple_motion_search_prune_part_logits_bias_64[] = { - 0.272852f, -0.260088f, 0.11881f, 0.146764f, 0.00289019f, - -0.559007f, -0.203668f, -0.268267f, -0.218921f, -0.260717f +static const float av1_simple_motion_search_prune_part_layer_0_kernel_64[] = { + -0.310947f, -0.232675f, 0.0171092f, 0.0834474f, 0.373977f, + 0.300429f, 0.215072f, -0.454074f, 0.187565f, 0.282742f, + 0.562562f, -0.0419322f, 0.000978486f, -0.298267f, 0.216934f, + -0.388722f, -0.146866f, -0.275946f, 0.202361f, 0.225847f, + 1.42868f, 0.473127f, -0.145747f, -0.104986f, 0.153459f, + 0.69382f, 0.162266f, 0.0207715f, -0.45095f, -0.412071f, + -0.235109f, -0.130199f, 0.231741f, 0.460193f, 0.0378202f, + 0.429516f, 0.387691f, -0.272479f, 0.0723884f, -0.453914f, + -0.150618f, -0.10745f, -0.258615f, 0.0838312f, -0.00554958f, + 0.105377f, -0.0415479f, 0.13228f, 1.09044f, -0.73053f, + -0.422553f, -0.435842f, 0.211416f, 0.420332f, 0.0181353f, + -0.030891f, 0.522788f, 0.613526f, 0.374032f, 0.287986f, + -0.403118f, -0.287362f, -1.11523f, -0.577713f, -0.020228f, + 0.86465f, -0.0590579f, 0.341274f, -0.0115644f, -0.260236f, + 0.192123f, -0.0849825f, 0.0501709f, 0.444382f, 0.0762727f, + 0.0926596f, -0.101157f, -0.142787f, 0.40861f, 0.555805f, + -0.00614654f, -0.122846f, 0.203163f, 0.234266f, 0.409795f, + -0.0206245f, -0.224679f, 0.025081f, 0.518044f, -0.287186f, + 0.016494f, -0.0886331f, 0.236438f, -1.01032f, 0.118332f, + 0.364217f, 0.061438f, 0.0381303f, 0.128418f, 0.0257077f, + -0.975751f, -0.694894f, 0.00351914f, 0.278179f, 0.29363f, + 0.525576f, 0.0604849f, 0.531734f, 0.406643f, 0.812497f, + -0.403196f, -0.16664f, -0.620887f, -0.428194f, 0.275401f, + 0.432063f, -0.00378342f, 0.295758f, 0.105615f, -0.00683626f, + 0.00396146f, 0.00598654f, -0.0131701f, -0.0115787f, 0.00386643f, + -0.69686f, -0.139623f, -0.440817f, 0.0542873f, 0.217962f, + 0.527035f, -0.0201046f, 0.0471354f, 0.0271858f, -0.0775197f, + -0.309797f, 0.184879f, -0.232854f, -0.407081f, 0.706227f, + -0.0877534f, 0.306843f, 0.455075f, -0.333961f, 0.0759148f, + 0.0444791f, -0.0693626f, -0.0850289f, -0.513063f, -0.643971f, + -0.630279f, -0.153889f, 0.123315f, 0.00548238f, 0.170707f, + 0.734339f, -0.176988f, 0.322519f, 0.178365f, 0.183519f, + -0.698683f, -0.12043f, -0.349914f, -0.0696762f, -0.53986f, + -0.104738f, 1.05264f, 0.983568f, -0.109035f, 0.0113748f, + 0.0815189f, -0.0628812f, 0.0769389f, 0.010261f, 0.146573f, + -0.433194f, -0.211572f, -0.000397392f, 0.445325f, 0.145091f, + -0.0625902f, 0.29394f, 0.302315f, 0.0892226f, -0.209504f, + -0.0150374f, 0.242608f, 0.216223f, 0.366857f, 0.209829f, + -0.540035f, 0.117599f, -0.329315f, 0.0471133f, -0.0115449f, + -0.0638235f, 0.0527461f, 0.348149f, 0.360802f, 1.06624f, + -0.615991f, -0.341396f, 0.18972f, 0.0709888f, -0.0414466f, + -0.0193809f, 0.0938933f, 0.209058f, 0.575042f, 0.483608f, + -0.285875f, -0.115905f, -0.363637f, 0.375425f, 0.336217f, + 0.0336358f, -0.00265618f, -0.406854f, -0.792959f, -0.219354f, + 0.0331615f, 0.0298859f, -0.211446f, -0.00280773f, -0.194011f, + 0.262109f, 0.548076f, 0.120183f, -0.661603f, 0.241855f, + -0.501428f, 0.00102718f, -0.347331f, -0.58306f, 0.0977254f, + 0.117491f, 0.0840667f, 0.00693675f, 0.000600294f, 0.649569f, + -0.0553811f, -0.197198f, 0.397236f, -0.523737f, -0.564192f, + -0.374679f, -0.249344f, 0.00861428f, 0.00393439f, -0.0834608f, + 0.124389f, -0.0393049f, 0.0425391f, -0.153383f, -0.182346f, + 0.420953f, 0.464221f, 0.288984f, 0.570921f, -0.239965f, + 0.247239f, -0.083434f, 0.714418f, 0.986323f, -0.460244f, + -0.260993f, -0.947743f, -1.0789f, -0.0391231f, 0.612407f, + -0.0306767f, 0.281419f, 0.0072426f, -0.37623f, 0.188744f, + 0.221666f, -0.424914f, 0.29703f, 0.261715f, 0.277809f, + -0.0617616f, -0.000611999f, -0.0547053f, -0.0901018f, -0.347669f, + 0.856072f, 0.596675f, -0.467639f, -1.09324f, -0.184224f, + -0.56051f, -0.0144704f, 0.102894f, -0.122982f, -0.0020749f, + -0.0423487f, 0.0328702f, -0.0154263f, 0.0349021f, -0.00315595f, + 0.0254802f, -0.729191f, 0.207296f, -0.0212349f, -0.207078f, + 0.20636f, -0.156883f, 0.429765f, -0.42672f, 0.138775f, + -0.0267343f, 0.631528f, 0.300646f, -0.4793f, -0.273833f, + -0.0135367f, -0.530819f, -0.534881f, 0.830896f, 0.0266992f, + 0.473744f, 0.210334f, 0.0234739f, 0.255394f, 0.123531f, + -0.489341f, -0.796627f, 0.372617f, 0.190136f, 0.275342f, + 0.739505f, 0.402354f, 0.782806f, 0.437374f, 1.04948f, + -0.55963f, 0.382704f, -0.698321f, 0.0817868f, -0.440108f, + -0.0635004f, -0.277851f, -0.524194f, 0.286157f, -0.01097f, + -0.0293145f, -0.0405071f, -0.035662f, -0.012871f, -0.0516409f, + -0.406671f, 0.709259f, -0.525177f, 0.521123f, -0.44813f, + 0.48412f, -0.0546513f, 0.305253f, -0.468328f, 0.316453f, + -0.36307f, 0.497515f, -0.0606276f, 0.315764f, -0.422066f, + 0.554025f, -0.679183f, 0.616914f, 0.00283324f, -0.000643824f, + 0.0639999f, 0.0488285f, -0.141031f, 0.068003f, -0.0792678f, + -0.425307f, -0.152235f, 0.269917f, -0.352327f, 0.44792f, + -0.116514f, -0.465868f, 0.154287f, 0.0161028f, -0.16848f, + -0.255487f, 0.189832f, 0.254883f, 0.0240822f, 0.432638f, + -0.136564f, 0.137036f, 0.0375734f, 0.989246f, -0.126287f, + 0.111416f, -0.0271002f, 0.718755f, -0.0412969f, 0.00645681f, + 0.253811f, -0.0186998f, 0.691971f, -0.282042f, -0.0783915f, + 0.274592f, -0.358449f, 0.34155f, -0.186374f, -0.136907f, + -0.192334f, -0.251168f, -0.100874f, -0.166578f, -0.336507f, + 0.402373f, 0.173695f, 0.108788f, 0.00885581f, -0.310063f, + 1.05545f, 0.0295867f, 0.180785f, -0.173469f, -0.469924f, + -0.224155f, 0.665862f, -0.126546f, 0.240691f, -0.0415301f, + -0.598534f, 0.0012723f, -0.122297f, -0.558947f, 0.268844f, + 0.241193f, 0.0524422f, -0.1683f, 0.575588f, -0.139012f, + 0.0636691f, -0.446709f, -0.094532f, 0.883809f, -0.112981f, + -0.224047f, 0.0811193f, -0.140571f, -0.09683f, -0.0796143f, + -0.102246f, -0.863392f, -0.0755124f, 0.23125f, -0.0301361f, + -0.153029f, -0.172238f, -0.0286382f, -0.338495f, -0.317216f, + -0.146629f, -0.242264f, -0.702306f, -0.285052f, 0.0623479f, + 0.265735f, 0.00674475f, 0.666196f, 0.883586f, 0.278416f, + -0.341692f, -0.509931f, -0.156263f, 0.635885f, -0.544143f, + -0.572632f, -0.213285f, 0.443396f, -0.268329f, 0.0638439f, + -0.185397f, 0.071126f, 0.386503f, -0.402212f, -0.140784f, + -0.411661f, 0.049398f, -0.0672907f, -0.267034f, -0.0560875f, + 0.0607937f, 0.0445484f, -0.547651f, 0.574718f, 0.417189f, + -0.0610166f, 0.0632293f, 0.391619f, -0.00671215f, -0.136883f, + -0.339346f, 0.0356183f, 0.511993f, 0.178676f, 0.286998f, + 0.136511f, -0.00796929f, 0.203985f, 0.0423532f, -0.175196f, + 0.378534f, 0.770417f, 0.593778f, 0.0256067f, -0.82394f, + -0.500691f, -0.425725f, -0.623708f, -0.0406241f, -0.00226464f, + 0.0207836f, 0.30732f, -0.00784268f, 0.0065445f, -0.0991039f, + -0.20871f, -0.206835f, 0.281219f, 0.119361f, 0.259346f, + -0.102713f, 0.186488f, -0.034455f, -0.00198392f, -0.279107f, + -0.638993f, -0.374404f, -0.48601f, -0.262345f, 0.624532f, + 0.620632f, -0.227014f, 0.433579f, -0.0455096f, 1.22123f, + -0.429156f, 0.12396f, 0.0815152f, -0.0837355f, 0.0282623f, + -0.407475f, 0.787321f, -0.434974f, 0.312904f, -0.230805f, + 0.213042f, -0.250929f, 0.302997f, -0.354709f, 0.0504905f, + -0.561706f, 0.595558f, 0.374951f, 0.802969f, -0.674902f, + 0.33136f, 0.156606f, 0.0218968f, -0.694188f, -0.0221949f, + -0.00639123f, 0.0146536f, 0.0104145f, 0.021635f, -0.0499428f, + -0.575116f, -0.239035f, -0.0588276f, 0.599722f, 0.541932f, + 0.437433f, 0.716268f, 0.193207f, 0.548351f, 0.326951f, + -0.197124f, 0.0355353f, -0.0952009f, -0.217265f, -0.389789f, + 0.0528124f, -0.21334f, -0.190296f, -1.17367f, 0.108905f, + 0.109397f, -0.0192577f, 0.0343813f, 0.085004f, -0.0556737f, + -0.0411158f, -0.534989f, 0.0361896f, 0.124415f, 0.291603f, + -0.0311974f, -0.326726f, 0.343131f, 0.0276456f, -0.231827f, + -0.373894f, -0.208898f, -0.273011f, 0.061323f, -0.0910538f, + -0.30746f, -0.108644f, -0.190736f, 1.58048f, -0.0739711f, + -0.0623489f, -0.137967f, -0.0601359f, -0.133004f, -0.0857153f, + 0.00955987f, -0.365561f, -0.0329051f, 0.463463f, 0.14758f, + -0.512256f, -0.227463f, -0.26008f, -0.567777f, 0.0646234f, + 1.02161f, 0.66157f, -0.16733f, 0.264921f, -0.242036f, + 0.214622f, 0.0712054f, -0.260377f, 0.0849665f, 0.735094f, + 0.11001f, 0.297301f, -0.333342f, 0.066978f, -0.123625f, + 1.07596f, 0.401263f, 0.0800875f, -0.340862f, -0.115587f, + -0.32692f, -0.300842f, 0.0277397f, 0.0630788f, -0.261198f, + 0.428695f, -0.0544757f, -0.124511f, 0.036992f, 0.126322f, + 0.0317603f, 0.0820762f, 0.117277f, -1.14594f, -0.108076f, + -0.0258198f, -0.00337525f, -0.00512531f, 0.1274f, -0.0660535f, + -0.640733f, 0.197142f, 0.147278f, 0.489271f, 0.226507f, + -0.0668414f, 0.0946318f, 0.0994164f, -0.820516f, 0.512939f, + -0.305172f, -0.715187f, -0.195125f, 0.279346f, 0.462144f, + 0.913882f, -0.453879f, 0.0582033f, -0.462866f, 0.0538736f, + 0.0115737f, 0.00626993f, -0.0185185f, 0.0114601f, -0.0181164f, + 0.41588f, -0.0447331f, 0.611756f, 0.43385f, 0.834465f, + 0.122019f, -0.352983f, 0.340429f, -0.245425f, -0.365328f, + -0.521825f, 0.0371057f, 0.172188f, -0.387949f, 0.221054f, + 0.0126359f, 0.422958f, 0.584198f, -0.581498f, -0.019466f, + -0.0271737f, -0.0740885f, 0.00540879f, 0.186086f, -0.0324402f, + -0.563462f, -0.458759f, -0.425296f, -0.0118862f, -0.641508f, + 0.0132084f, 0.0581128f, 0.0231444f, 0.468587f, 0.258838f, + 0.0296665f, 0.0562801f, 0.630014f, 0.381816f, -0.269761f, + -0.135515f, 0.046186f, 1.07632f, -0.050616f, 0.104987f, + 0.29991f, 0.119316f, 0.117248f, 0.0795009f, 0.242573f, + 0.0416634f, -0.0577639f, -0.0974078f, 0.106255f, -0.13098f, + 0.0141486f, -0.00418257f, 0.144848f, -0.463934f, 0.0452591f, + 0.252617f, 0.205222f, -0.189843f, 0.0652245f, -0.135386f, + 0.0500646f, -0.200368f, -0.0142312f, -0.0286832f, -0.254355f, + -1.02752f, -0.73549f, 0.0364518f, 0.0416227f, -0.13185f, + -0.0886515f, -0.502314f, -0.102916f, 0.410911f, -0.355655f, + 0.400416f, -0.340217f, 0.208829f, 0.245972f, 0.149739f, + -0.49458f, 0.589482f, 0.550827f, 0.912709f, -0.351275f, + -0.128076f, -0.285172f, -0.672752f, 0.090583f, -0.245286f, + -0.737297f, -0.201515f, -0.025122f, -0.109854f, 0.36738f }; -static const float simple_motion_search_prune_part_layer_0_bias_64[] = { - -2.12804f, 0.445147f, -0.0210471f, 0.533662f, 0.662023f, 0.020519f, - -0.0452071f, -0.343995f, 0.112379f, -0.16776f, 0.112004f, 0.932147f, - -1.22944f, -0.822248f, 0.370083f, -0.0951491f, 0.0631258f, -0.875801f, - 0.996276f, 0.116103f, 0.925914f, 0.054293f, -1.02697f, -0.359516f +static const float av1_simple_motion_search_prune_part_logits_bias_64[] = { + 0.346819f, 0.442965f, -0.0216032f, 0.0229235f, -0.402797f, + -0.666074f, -0.455388f, -0.00353411f, -0.595511f, -0.845667f }; -static const NN_CONFIG simple_motion_search_prune_part_nn_config_64 = { +static const NN_CONFIG av1_simple_motion_search_prune_part_nn_config_64 = { NUM_FEATURES_64, NUM_LOGITS_64, NUM_HIDDEN_LAYERS_64, @@ -3301,12 +3226,12 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_64 = { NUM_LAYER_0_UNITS_64, }, { - simple_motion_search_prune_part_layer_0_kernel_64, - simple_motion_search_prune_part_logits_kernel_64, + av1_simple_motion_search_prune_part_layer_0_kernel_64, + av1_simple_motion_search_prune_part_logits_kernel_64, }, { - simple_motion_search_prune_part_layer_0_bias_64, - simple_motion_search_prune_part_logits_bias_64, + av1_simple_motion_search_prune_part_layer_0_bias_64, + av1_simple_motion_search_prune_part_logits_bias_64, }, }; @@ -3315,163 +3240,227 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_64 = { #undef NUM_LAYER_0_UNITS_64 #undef NUM_LOGITS_64 -// BLOCK_32X32 #define NUM_HIDDEN_LAYERS_32 1 -#define NUM_FEATURES_32 19 -#define NUM_LAYER_0_UNITS_32 24 +#define NUM_FEATURES_32 25 +#define NUM_LAYER_0_UNITS_32 28 #define NUM_LOGITS_32 10 -static const float simple_motion_search_prune_part_logits_kernel_32[] = { - -1.22965f, 0.49978f, -0.376271f, 0.0615445f, -0.212491f, 0.58427f, - 0.142683f, 2.62142f, -0.459751f, -0.570143f, 0.72257f, -0.64127f, - 0.266919f, 0.3235f, 0.64405f, -0.0398269f, -1.82822f, -0.366573f, - 0.753387f, -0.274241f, -0.484971f, -0.503907f, -0.911176f, -0.455827f, - -0.706345f, 0.0687611f, -0.362788f, -0.369416f, -0.530408f, 0.0812615f, - -0.863012f, -0.613333f, -0.268833f, 0.0982181f, 0.19374f, -0.147078f, - -0.0200551f, 0.363817f, 0.179229f, 0.429671f, 0.905826f, -0.441191f, - 0.48874f, 0.539192f, -0.418992f, -0.468762f, -0.482158f, -0.770778f, - -0.743739f, 0.0175955f, -0.40662f, 0.0276107f, 0.0110658f, -0.119298f, - 0.698777f, -0.187602f, -0.300483f, -0.147972f, 0.324042f, -0.0265165f, - -0.375496f, 0.245762f, -0.111271f, -0.829879f, -0.434606f, -0.367099f, - 0.113229f, -0.755101f, -0.0623393f, -0.13764f, -0.205864f, -0.332027f, - 0.966638f, 0.477078f, 0.262501f, -0.110232f, 0.141242f, -0.699602f, - -0.14943f, -2.36868f, 0.556236f, 0.345883f, -0.466765f, 0.279446f, - -0.56809f, -0.356351f, -0.503855f, -0.607959f, -0.0328514f, 0.313352f, - -0.644447f, 0.221808f, 0.254575f, 0.476802f, 1.40433f, 0.317169f, - 0.109761f, -0.0105197f, -0.22896f, -0.389234f, 0.423948f, -0.272114f, - -1.02704f, -1.50706f, 0.0563541f, -0.0371609f, -0.306187f, 0.0570354f, - -0.367998f, 0.0949103f, -0.254703f, -0.0853516f, 1.56471f, -0.594372f, - -0.23582f, 0.267108f, 0.015297f, -0.318317f, 0.287599f, -0.687022f, - 0.360804f, -0.177637f, -0.118144f, -0.418225f, -0.985658f, -0.391334f, - -0.772539f, -0.44002f, 0.0722112f, -0.0825626f, 0.0466844f, 0.0525818f, - -0.788047f, 0.120401f, -0.785688f, -0.346177f, 0.240363f, 0.0248826f, - -0.0815654f, 0.39317f, -0.122372f, 0.199969f, 0.202777f, -0.1979f, - 0.313558f, -0.180202f, 0.191204f, -0.313598f, 0.155464f, -0.600106f, - 0.0230461f, -0.718126f, 0.266874f, -0.313614f, 0.0352148f, 0.131058f, - -0.221112f, 0.115419f, -1.41928f, -0.909453f, 0.341747f, -0.25318f, - -0.312476f, -0.288919f, -0.0135884f, -0.278496f, 0.381449f, -0.0725586f, - 0.254479f, -0.0658647f, -0.694657f, -0.0653643f, -0.0233378f, -0.484902f, - -0.104919f, -1.52446f, 0.0140919f, -0.142396f, -0.11836f, 0.113235f, - -1.21564f, 0.0618471f, 0.0421833f, -0.883143f, 0.288008f, -0.278322f, - -0.185151f, -0.616223f, 0.334549f, 0.370898f, 0.24646f, -0.027439f, - 0.366905f, -0.40628f, 0.0260464f, -0.506151f, 0.0191214f, -0.104617f, - -0.848722f, -1.66357f, -0.194607f, 0.0346545f, -0.412502f, 0.200471f, - -0.285588f, 0.0309609f, -0.150546f, 0.569096f, 0.210382f, 0.14322f, - 0.908182f, 1.23553f, -0.432935f, -0.0963189f, -0.610778f, -0.532583f, - -0.302028f, -0.600906f, -0.0777476f, 0.0230625f, 0.375802f, -0.466292f, - 1.01104f, -1.16706f, 0.0121855f, 0.0100479f, -0.147181f, 0.255058f, - -0.285898f, -0.167804f, -0.240171f, -1.15287f, -1.51181f, 0.0859809f, - 0.0811324f, -0.829305f, 0.272793f, 0.407484f, 0.324943f, 0.230197f +static const float av1_simple_motion_search_prune_part_logits_kernel_32[] = { + 0.486581f, 0.340847f, -0.109226f, 0.467224f, -0.541561f, + 0.0943619f, -0.429442f, -0.207442f, 0.959963f, 0.618666f, + -0.0636751f, 0.144508f, -0.0278289f, 0.332293f, -0.751493f, + 0.245438f, -0.917758f, 0.612128f, -0.32648f, 0.534618f, + -0.615239f, 2.71641f, 0.233759f, 0.820558f, -0.249758f, + -0.427783f, -0.359361f, 0.0375732f, 0.806973f, 0.352512f, + -0.0532192f, 0.0576861f, -0.464178f, -0.334877f, -0.697042f, + 0.0538218f, 0.0919659f, -0.00765812f, 0.0603847f, -0.460315f, + 0.37979f, -0.0867612f, -0.670683f, -0.188619f, -0.570586f, + 0.233418f, 0.153581f, 0.290905f, -0.624885f, -0.557842f, + -0.555567f, 0.463773f, -0.123909f, -0.277731f, 0.0374468f, + 0.409903f, 0.287638f, -0.593066f, -0.223434f, 0.154263f, + -0.250464f, -0.077696f, 0.229652f, -0.304174f, 0.308053f, + 0.33155f, -0.502825f, 0.361216f, -0.499294f, 0.00595444f, + -0.307201f, 0.5766f, -0.438384f, -0.093701f, -0.118586f, + 0.202337f, -0.486623f, 0.261552f, 0.139756f, -0.655642f, + -0.0627001f, -0.213053f, -0.243037f, 0.205918f, 0.0718368f, + 0.188041f, 0.141529f, -0.132239f, 0.425827f, -0.218353f, + 0.153114f, 0.33268f, 0.0226116f, 0.167394f, 0.269854f, + -0.457001f, 0.1973f, -0.526087f, 0.467528f, 0.290934f, + 1.16267f, 0.0823663f, -0.754389f, -0.83716f, 0.270157f, + -1.41229f, 0.148511f, -0.286832f, 0.664796f, 0.492254f, + 0.360567f, -0.533993f, 0.0435672f, -0.103001f, 0.220668f, + 0.594621f, -0.0213356f, -0.347638f, -0.694457f, 0.0759505f, + 0.161358f, -0.389384f, -0.0455192f, -0.61252f, -0.174173f, + -0.00788878f, -1.22487f, 0.332233f, -0.0457021f, -0.225918f, + -0.197657f, -0.115408f, -0.240589f, -2.05681f, 0.00914629f, + -1.92213f, 0.0268578f, -0.49076f, -0.0120123f, 0.291157f, + 0.267116f, -0.0775724f, 0.181115f, -0.392441f, -0.488114f, + -0.28842f, -0.115465f, 0.128974f, -0.0829899f, -0.14096f, + -0.140145f, -0.700281f, 0.0368945f, -0.437598f, 0.243485f, + -1.00301f, 0.332324f, 0.125014f, -0.0604481f, -0.0652028f, + -0.207295f, -1.0209f, -0.341525f, 0.191326f, -0.147578f, + 0.0878327f, 0.129827f, -0.0848319f, 0.187381f, -1.28663f, + 0.00537885f, -0.134277f, -0.0411126f, -0.3434f, -0.0456494f, + 0.37861f, 0.409095f, 0.237177f, -0.396855f, -0.205418f, + -1.31701f, -0.319032f, -0.123404f, -0.240005f, -0.305206f, + -0.0258176f, -0.26367f, -0.142396f, 0.191672f, -1.44061f, + 0.0554776f, -0.571839f, -0.284789f, -0.425677f, -0.0307376f, + 0.20275f, -0.223146f, 0.144612f, 0.0212636f, 0.0238303f, + -0.253802f, -0.188922f, -0.0637066f, -0.340836f, 0.124774f, + 0.130474f, -0.154099f, -0.0292733f, 0.158148f, -0.246989f, + -0.259059f, 0.220224f, 0.228449f, -0.41956f, -0.321848f, + -0.2396f, -0.316449f, -1.3363f, 0.0264099f, -1.46865f, + 0.113073f, 0.0722885f, -0.166986f, -0.164877f, 0.0360911f, + 0.534472f, -0.551152f, -0.328501f, 0.0781121f, -0.378112f, + -0.459502f, 0.28015f, -0.212302f, -0.521641f, 0.618993f, + -0.347709f, 0.266253f, -0.0280894f, 0.348511f, -0.0155031f, + -0.100693f, 0.0447673f, 0.277519f, -0.233998f, -0.0796738f, + -1.73644f, -0.160776f, 0.53092f, -0.180406f, 0.056447f, + 0.385356f, -0.262337f, -0.241479f, -0.271426f, -0.457354f, + -0.266788f, 0.367371f, -0.103065f, 0.47783f, -0.188327f, + -0.159636f, 0.00142907f, -0.409756f, 0.454889f, -0.24566f, + -0.0760084f, 0.286355f, 0.462102f, 0.0431695f, -0.127395f, + -0.200476f, -0.350557f, 0.217275f, -0.23975f, 0.255148f, + -0.280626f, 0.42476f, 0.157411f, 0.0358675f, -0.192591f }; -static const float simple_motion_search_prune_part_layer_0_kernel_32[] = { - -0.0711848f, 0.187893f, -0.0532872f, -0.0403218f, 0.132223f, - 0.0150309f, 0.132917f, -0.00883543f, -0.0614934f, 0.207838f, - -0.102772f, 0.127833f, -0.332145f, 0.00237219f, -0.338402f, - 0.123288f, -0.248341f, -0.0182967f, -1.16283f, -0.166611f, - -0.220962f, -0.268939f, -0.207455f, -0.214904f, -0.0639896f, - -0.0729676f, -0.000552725f, 0.217902f, 0.350537f, -0.0217492f, - 0.136239f, 0.0641448f, 0.515814f, 0.525507f, 0.240539f, - 0.109375f, 0.322722f, -1.20791f, 0.323287f, 0.0231209f, - -0.194629f, 0.143504f, 0.193943f, -0.15059f, -0.0156431f, - -0.210354f, 0.13426f, -0.379795f, 0.0585494f, 0.0947257f, - 0.948153f, 0.492681f, -0.977907f, -0.30367f, 0.216922f, - -0.366185f, 0.00734769f, 0.528627f, 0.334327f, 0.0222445f, - 0.400606f, -0.0313966f, -0.047664f, -0.512993f, -0.433836f, - 0.340769f, -0.131347f, -0.518235f, -0.220933f, -0.379338f, - -0.116978f, 0.143766f, 0.456281f, -0.0921022f, -0.0109533f, - -0.107467f, 0.335672f, -0.313228f, 0.175586f, 0.108769f, - 0.129646f, -0.053502f, 0.272574f, 0.220172f, 1.51046f, - 0.255032f, -0.162058f, -0.770721f, 0.238623f, -0.65159f, - -0.0354393f, -0.577323f, 0.0954972f, -0.661719f, 0.227893f, - -0.0584787f, 0.234849f, -0.16515f, -0.247194f, 0.12563f, - 0.39043f, -0.178219f, -0.0629665f, 0.395761f, 0.24224f, - -0.336032f, 0.552893f, -0.300073f, -0.235499f, -0.33557f, - 0.0398952f, -0.853526f, -0.550247f, 1.13965f, 0.197325f, - -0.0750203f, 0.145096f, 0.128642f, 0.113606f, 0.0972738f, - 0.219874f, 0.252284f, 0.833398f, 0.398332f, 0.802753f, - 0.650573f, -0.725374f, -0.548798f, -0.668723f, -0.705524f, - -0.929613f, -0.138145f, 0.161306f, 0.578878f, 0.0605056f, - 0.720406f, 0.163571f, 0.707962f, -0.0777347f, 0.52085f, - 0.279096f, 0.180012f, -0.459535f, 0.219678f, -0.273058f, - -0.030387f, -0.262664f, 0.367791f, -0.899145f, -1.07191f, - -1.15497f, 0.460442f, 0.020009f, -0.329794f, 0.846777f, - 0.287855f, 0.603544f, 0.645424f, 0.00753003f, -0.0666031f, - -0.141114f, -0.149588f, -0.431897f, -0.591811f, 0.134026f, - 0.0933469f, -0.130808f, -0.0335611f, -0.488446f, -0.275566f, - -0.937488f, 0.245793f, -0.548915f, 0.0108641f, -0.216292f, - 0.00680863f, -0.113137f, -0.137064f, 0.083321f, 0.689742f, - -0.213193f, 0.172408f, -0.123794f, 0.383401f, -0.496176f, - 0.427836f, -0.644447f, 0.967995f, 0.181371f, 0.301512f, - -0.376098f, -0.0571203f, 0.0012891f, 0.467542f, -0.400791f, - -0.204521f, 0.253847f, 0.107368f, -0.434741f, -0.389665f, - 0.30953f, 0.053949f, -0.0415711f, 0.0432576f, -0.319656f, - -0.228939f, -0.0928546f, 0.164408f, 1.26655f, 0.991928f, - -0.0596439f, 0.0786943f, 0.001457f, 0.282831f, 0.0975484f, - 0.13724f, 0.0891527f, -0.0471925f, 0.255467f, -0.469073f, - -0.0759757f, 0.331197f, 0.139434f, -0.0118866f, 0.359463f, - -0.774947f, -0.474647f, -1.36563f, 0.24901f, 0.776025f, - 0.150621f, 0.192407f, 0.752499f, 0.0435322f, -0.0334263f, - 0.470741f, -0.781907f, -0.149471f, -0.649484f, -0.866079f, - 0.536967f, 0.541611f, -0.00237101f, -0.119688f, -0.594591f, - -0.967503f, 0.545025f, -0.335037f, -0.172105f, -0.532514f, - -0.442211f, -0.0864824f, 0.038418f, -0.337492f, -0.412653f, - 0.0778177f, 0.0824839f, -0.232478f, 0.553077f, 0.179073f, - 0.222848f, -0.261019f, 0.854277f, -0.643185f, 0.476021f, - -0.0174448f, 0.621669f, -0.527978f, 0.45279f, -0.286967f, - 0.328291f, 0.0627781f, 0.495794f, 0.0156424f, -0.170515f, - -0.435815f, -0.264061f, -0.964473f, 0.259361f, -0.297514f, - 0.667044f, 0.719631f, -0.812974f, -0.350331f, 0.594795f, - -0.106071f, -0.409225f, 0.283481f, 0.5735f, -0.231666f, - -0.270059f, 0.687725f, 0.349693f, 0.0637911f, 0.208738f, - 0.299087f, -0.249188f, -0.426365f, -1.01906f, 0.0919539f, - -0.198362f, 0.256663f, -0.302723f, 0.457283f, 0.433322f, - 0.242223f, 0.740515f, 0.247248f, 0.436274f, 0.588906f, - 0.852493f, 0.385838f, 0.243232f, -0.501191f, 0.212121f, - 0.297253f, -0.664029f, -0.470196f, 0.0175681f, -1.01849f, - -0.619865f, -1.26982f, -0.088134f, -0.29233f, -0.196112f, - -0.141886f, 0.0602684f, 0.469327f, 0.0227135f, 0.275863f, - 0.161156f, -0.864189f, -0.72576f, 0.62214f, 0.804845f, - 0.183776f, -0.155777f, -0.0826676f, -0.23302f, 0.0845181f, - -0.126365f, 0.0925764f, 0.889037f, -0.208894f, 0.441273f, - 0.476529f, 0.510144f, 0.321464f, 0.764386f, 0.198938f, - -0.669809f, -0.13214f, -0.426596f, -0.547804f, -0.0953238f, - 0.164997f, 0.275626f, -0.0469242f, -0.923263f, -1.05855f, - -0.487197f, 0.261922f, -0.108634f, 0.409852f, 0.142348f, - 0.153656f, -0.119714f, 0.490507f, -0.26725f, -0.0651784f, - -0.962803f, -0.596098f, -0.686329f, 0.66723f, 0.290971f, - 0.692586f, 0.56926f, -0.0494205f, -0.498585f, -0.1832f, - -0.571507f, -0.438308f, 0.607958f, 0.985154f, 0.131991f, - 0.0469712f, 0.415769f, -0.518799f, -0.353338f, -0.219197f, - -0.159141f, 0.085484f, -0.405673f, -0.222816f, 0.813276f, - 0.323344f, -0.235178f, -0.40799f, -0.083177f, 0.514834f, - 0.177916f, 0.0197744f, -0.523574f, -0.445548f, -0.21085f, - 0.760991f, 0.170654f, -0.00312635f, -0.175464f, 0.665364f, - -0.713881f, -0.701069f, -0.628863f, 1.03196f, -0.0414137f, - -0.0163186f, 0.16796f, -0.0263498f, 0.484873f, 0.153922f, - 0.0593931f, 0.171615f, 0.330269f, -0.0728948f, 0.42332f, - 0.294273f, -0.0185935f, -0.609248f, -0.305841f, -0.293534f, - 0.0766015f, 0.130506f, 0.16716f, 0.0168997f, -0.429074f, - -0.744995f, -0.972633f, 0.50621f, -0.275645f, 0.402252f, - -0.0190824f, 0.637343f, -0.410791f, 0.546844f, -0.555088f, - 0.491182f, -0.0369695f, 0.974657f, -0.142378f, -0.148588f, - -0.217919f, 0.0146815f, -0.419912f, 0.111356f, -0.640505f, - -0.352691f +static const float av1_simple_motion_search_prune_part_layer_0_bias_32[] = { + 0.940498f, 0.15602f, -0.234831f, 0.0268585f, 0.144769f, 0.243081f, + 0.611406f, 0.366093f, 0.361868f, 0.39668f, 0.401479f, 0.369467f, + 0.0909503f, 0.710595f, 0.032786f, 0.525891f, -1.0232f, 0.732557f, + -0.064425f, 0.865222f, -0.042917f, -0.237191f, -0.527006f, -0.0172101f, + 0.59681f, -0.472405f, 0.0969218f, -0.250624f }; -static const float simple_motion_search_prune_part_logits_bias_32[] = { - 0.0868818f, 0.370904f, 0.126136f, 0.57768f, -0.316245f, - -0.526958f, -0.451775f, -0.595569f, -0.805166f, -0.592605f +static const float av1_simple_motion_search_prune_part_layer_0_kernel_32[] = { + 0.355607f, 0.126701f, -0.0825159f, 0.200675f, -0.011308f, + -0.280057f, 0.559816f, 0.142689f, 0.0422419f, -0.151692f, + -0.0275637f, -0.283101f, -0.20822f, -0.200394f, 0.465427f, + 0.344491f, -0.525319f, -0.358813f, -0.39767f, 0.0974486f, + 0.00559058f, -0.00546089f, 0.0506486f, 0.114475f, -0.0436463f, + -0.574152f, -0.376294f, 0.16563f, -0.0967032f, 0.00579838f, + 0.0639909f, -0.037129f, 0.407574f, -0.231428f, 0.489326f, + -0.221566f, -0.270382f, -0.784628f, -0.155502f, 0.481698f, + -0.0296057f, 0.431855f, 0.840807f, 0.112291f, 0.773874f, + -0.0610936f, -0.012892f, 0.365154f, 0.0267687f, -0.0751114f, + 0.25043f, 0.516472f, -0.186133f, -0.12762f, -0.168804f, + -0.146309f, 0.139314f, -0.367113f, -0.601079f, 0.0559856f, + 0.176081f, 0.22397f, 0.434113f, 0.0363256f, 0.313051f, + 0.0143976f, 0.190076f, 0.474607f, -0.681134f, -0.0709097f, + -0.253289f, -0.216277f, -0.0593789f, -0.107795f, -0.194842f, + 0.513945f, 0.239171f, -0.720561f, 0.0136723f, -0.391147f, + -0.272043f, -0.164766f, 0.124248f, 0.147178f, -0.35497f, + 0.397725f, -0.117603f, 0.262937f, -0.331964f, 0.182418f, + 0.315671f, -0.0385649f, 0.488769f, -0.334568f, 0.00596018f, + 0.0661557f, -0.0446985f, -0.0928255f, -0.0221032f, -0.019045f, + -0.20881f, 0.197907f, -0.381881f, 0.0598071f, -0.0434551f, + 0.159283f, -0.110631f, 0.266996f, -0.0265494f, 0.135199f, + -0.00833162f, 0.804482f, -0.114698f, -0.15066f, -0.479553f, + 0.448407f, -0.344069f, -0.0280952f, -0.208211f, -0.102269f, + -0.679066f, -0.37476f, -0.0228875f, 0.0535049f, 0.111015f, + -0.18125f, -0.167584f, 0.0110497f, 0.262723f, -0.413839f, + -0.0611238f, 0.358499f, 0.0807514f, 0.208254f, 0.214499f, + 0.11137f, -0.14262f, -0.0513973f, 0.243718f, -0.373716f, + -0.00413366f, 0.216501f, -0.164149f, -0.064935f, -0.0840282f, + 0.0566148f, 0.0377686f, 0.289835f, 0.769388f, 0.891198f, + -0.592739f, 0.40744f, -0.153095f, 0.657311f, 0.140737f, + 0.28209f, 0.158344f, 0.353546f, 0.0868246f, 0.116887f, + 0.402004f, 0.437184f, 0.589219f, 0.760594f, -0.575419f, + -0.754308f, -0.709219f, -0.297814f, -0.418609f, -0.0262104f, + 0.0411959f, 0.0597708f, -0.143728f, -0.136642f, 0.099614f, + -0.257601f, -0.2404f, 0.305893f, 0.254009f, -0.0301398f, + -0.0653091f, -0.459002f, -0.163404f, 0.123152f, -0.0284252f, + -0.457272f, 0.00788622f, -0.828399f, -0.0534199f, 0.586877f, + 0.982728f, 0.424581f, 0.0891856f, 0.383182f, -0.122053f, + 0.0808408f, -0.00384914f, -0.0560201f, -0.0524772f, -0.263444f, + -0.239287f, -0.882777f, 0.0180592f, -0.0948711f, -0.177946f, + 0.0296473f, 0.096082f, 0.0455604f, -0.108608f, 0.00777951f, + -0.140896f, 0.117187f, -0.342467f, -0.0691604f, 0.0761611f, + -0.0892053f, 0.111386f, -0.167456f, 1.40616f, -0.00478793f, + 0.00547665f, -0.0441829f, 0.0151323f, -0.0674099f, -0.0380578f, + 0.16072f, 0.31882f, 0.245486f, -0.424318f, 0.101845f, + -0.203343f, -0.197402f, -0.163025f, -0.0771961f, -0.264435f, + 0.319429f, 0.250076f, 0.782726f, 0.386003f, 0.00700673f, + -0.375715f, 0.151453f, -0.296265f, -0.560183f, -0.00767249f, + -0.109593f, -0.119419f, -0.0161516f, 0.0380283f, -0.156417f, + 0.131708f, 0.396268f, -0.221796f, 0.232099f, 0.128852f, + 0.0567268f, 0.297297f, 0.173269f, 0.213411f, 0.0384426f, + -0.290985f, -0.0426841f, -0.488292f, -0.087101f, -0.311582f, + 0.83009f, -0.153163f, 0.903335f, -1.15644f, -0.0378635f, + -0.0552129f, -0.126362f, -0.176945f, 0.0653115f, 0.0989368f, + -0.333543f, -0.330586f, 0.29775f, -0.103535f, 0.210824f, + -0.00300509f, 0.317105f, 0.216852f, 0.479718f, 0.0485808f, + -0.15662f, 0.718199f, 0.327513f, 0.115169f, -0.423598f, + -0.456633f, -0.575814f, -0.494454f, 0.304411f, 0.0493055f, + -0.381171f, 0.467251f, -0.122872f, -0.167441f, 0.017253f, + -0.0583646f, -0.1586f, 0.214046f, -0.0284424f, -0.217112f, + 0.606567f, -0.107533f, 0.36615f, -0.0709227f, 0.604761f, + -0.244657f, -0.296651f, -0.595611f, -0.156629f, -0.693468f, + -0.310603f, 0.499272f, 0.282941f, 0.295043f, -0.178704f, + 0.281186f, 0.014329f, -0.120819f, 0.154234f, 0.0131325f, + -0.472231f, -0.631281f, 0.422955f, 0.711432f, -0.118025f, + 0.0864996f, 0.343971f, -0.301477f, -0.246638f, 0.165068f, + 0.218044f, 0.224236f, -0.0848522f, 0.00671216f, 0.401141f, + -0.218857f, -0.0298495f, -0.135725f, -0.377618f, 0.022473f, + 0.106955f, -0.0582005f, 0.0468484f, -0.0217442f, 0.130911f, + -0.0926905f, 0.383007f, -0.159353f, -0.222711f, -0.0286419f, + 0.372315f, -0.469095f, 0.797571f, -0.301315f, 0.239327f, + -0.997507f, -0.363409f, 0.353717f, 0.676686f, -0.0500028f, + 0.0638539f, -0.431927f, 0.243852f, 0.000884826f, -0.00166585f, + 0.0613292f, -0.029558f, -0.0248432f, -0.0125607f, -0.0309674f, + -0.743308f, 0.0409806f, 0.0921015f, 0.167816f, 0.406849f, + 0.095677f, 0.0308913f, 0.139956f, -0.400472f, 0.396617f, + 0.936517f, 0.355057f, -0.423816f, -0.232472f, -0.220188f, + -0.399746f, -0.409623f, -0.158797f, 0.361153f, 0.0327019f, + 0.0690844f, -0.032197f, 0.0248558f, 0.00438518f, 0.0222724f, + -0.326832f, -0.314295f, 0.156563f, 0.0562703f, 0.332694f, + 0.299424f, 0.228206f, 0.322038f, 0.0136098f, 0.0060297f, + -0.165851f, -0.306512f, 0.0796508f, -0.37158f, 0.239395f, + -0.349442f, 0.198515f, -0.253854f, -1.13694f, 0.0202873f, + -0.0504009f, -0.130528f, -0.017126f, -0.0370001f, -0.087458f, + -0.119952f, -0.130404f, 0.0333733f, -0.184736f, 0.182162f, + 0.227776f, -0.166563f, -0.156162f, 0.118215f, -0.220183f, + 0.00474779f, -0.107792f, 0.260493f, 0.11884f, 0.156587f, + 0.303936f, -0.131788f, -0.314774f, 0.310606f, 0.0935523f, + 0.790767f, 0.26461f, 0.0236426f, 0.0629469f, 0.0344072f, + -0.151513f, 0.211498f, 0.0245435f, 0.0629973f, 0.052019f, + -0.03308f, 0.123487f, 0.0885027f, 0.159172f, -0.0510615f, + 0.0298033f, -0.130515f, -0.121799f, -0.104915f, 0.208822f, + -0.310496f, -0.314106f, 0.303307f, -0.0196736f, 0.0420045f, + 0.461777f, -0.433699f, 0.00345407f, 0.703139f, -0.655637f, + -0.210767f, -0.201278f, 0.163694f, -0.236534f, 0.300877f, + 0.0769982f, -0.282453f, 0.149721f, -0.0303466f, -0.191473f, + -0.406056f, -0.213472f, 0.1619f, -0.245953f, 0.00544399f, + -0.121434f, 0.193012f, -0.307165f, 1.45431f, -0.161468f, + -0.12444f, -0.146129f, -0.0528212f, -0.0925165f, -0.134528f, + -0.479475f, 0.315525f, 0.133845f, 0.382158f, -0.0799693f, + -0.151041f, 0.255772f, 0.409536f, -0.240663f, -0.323741f, + -0.205876f, 0.03699f, -0.217541f, 0.108511f, 0.640628f, + 0.705993f, -0.423899f, -0.78314f, -0.100733f, -0.00859087f, + 0.0251879f, 0.0458335f, 0.00210128f, -0.047576f, -0.0560518f, + -1.23869f, -0.829914f, 0.0346551f, 0.350505f, 0.193688f, + 0.459154f, 0.137898f, 0.503818f, 0.260867f, 0.649539f, + 0.0150802f, 0.0239274f, -0.276069f, -0.0621478f, -0.193106f, + -0.0375665f, -0.654529f, 0.189493f, 0.446625f, -0.0208265f, + 0.019838f, -0.0201955f, 0.00180428f, -0.0110678f, -0.0172414f, + 0.0276489f, -0.252882f, -0.0351807f, -0.0518874f, 0.279098f, + -0.245122f, 0.101287f, -0.114202f, -0.0812187f, 0.572429f, + -0.0821731f, 0.564183f, 0.0222552f, 0.190111f, -0.0417497f, + -0.00385925f, -0.182995f, -0.240482f, -0.291572f, -0.0450444f, + 0.0962974f, -0.165973f, -0.0954637f, -0.163841f, -0.833405f, + -1.31541f, -0.336473f, -0.0920702f, 0.816105f, 0.393377f, + 0.0340241f, -0.0844545f, 0.61729f, -0.17596f, 0.241149f, + -0.42825f, -0.59091f, -0.290702f, 0.0796465f, 0.0982819f, + 0.466934f, 0.261666f, 0.0373333f, 0.332509f, -0.0266694f, + -0.0476951f, -0.00642167f, -0.0132542f, -0.000320841f, 0.00475532f, + 0.000502778f, 0.296534f, -0.13297f, -0.113082f, -0.327923f, + 0.35901f, -0.302246f, 0.189799f, -0.37994f, 0.16107f, + -0.20414f, 0.548575f, -0.460821f, 0.591878f, -0.213113f, + -0.169373f, -0.07332f, 0.228841f, 0.682302f, -0.0665316f, + -0.142456f, -0.0873117f, 0.00607451f, 0.0376443f, 0.0536673f, + -0.0109536f, -0.400279f, 0.550058f, 0.820871f, -0.666373f, + -0.471962f, -0.315925f, -0.313142f, 0.952742f, 0.473928f, + -0.119006f, 0.153241f, -0.0383078f, 0.631869f, -0.343423f, + -0.233473f, -0.218195f, -0.077688f, -0.728291f, 0.0382408f, + -0.00662886f, -0.0419666f, 0.0309776f, -0.0281592f, 0.0154229f, + -0.198534f, 0.0206324f, 0.0152272f, -0.235067f, 0.0330486f, + 0.139198f, -0.0612118f, 0.133154f, -0.258675f, 0.0900275f, + -0.127771f, 0.157322f, -0.00767807f, -0.329258f, 0.327458f, + 0.0528581f, -0.181125f, 0.409995f, -0.162979f, -0.0193475f, + 0.186009f, 0.0519501f, 0.651877f, -0.37821f, -1.10341f, + -0.189776f, -0.0922788f, 0.460256f, 0.168011f, 0.440295f, + 0.478135f, 0.374573f, 0.384048f, 0.116953f, 0.68886f, + -0.427727f, -0.36676f, -0.500013f, -0.228685f, -0.218859f, + 0.208396f, -0.0173765f, -0.0680241f, -0.00538013f, -0.0674409f, + -0.092764f, 0.0295707f, -0.0462887f, -0.00636006f, 0.0334169f }; -static const float simple_motion_search_prune_part_layer_0_bias_32[] = { - -1.85942f, 0.727049f, -0.0421259f, 0.759194f, 0.241057f, 0.0752973f, - 0.321934f, -0.593116f, -0.873202f, -0.238779f, 0.851339f, -0.536633f, - -0.18552f, -0.0941714f, 0.0153855f, -1.34736f, -0.870722f, 0.0973251f, - 0.491483f, 0.650638f, -0.205986f, -0.0499654f, -1.00592f, 0.65992f +static const float av1_simple_motion_search_prune_part_logits_bias_32[] = { + 0.176459f, 0.154405f, 0.281821f, 0.375264f, -0.882863f, + -0.240261f, -1.17075f, -0.280216f, -0.743836f, -0.317511f }; -static const NN_CONFIG simple_motion_search_prune_part_nn_config_32 = { +static const NN_CONFIG av1_simple_motion_search_prune_part_nn_config_32 = { NUM_FEATURES_32, NUM_LOGITS_32, NUM_HIDDEN_LAYERS_32, @@ -3479,12 +3468,12 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_32 = { NUM_LAYER_0_UNITS_32, }, { - simple_motion_search_prune_part_layer_0_kernel_32, - simple_motion_search_prune_part_logits_kernel_32, + av1_simple_motion_search_prune_part_layer_0_kernel_32, + av1_simple_motion_search_prune_part_logits_kernel_32, }, { - simple_motion_search_prune_part_layer_0_bias_32, - simple_motion_search_prune_part_logits_bias_32, + av1_simple_motion_search_prune_part_layer_0_bias_32, + av1_simple_motion_search_prune_part_logits_bias_32, }, }; @@ -3493,123 +3482,256 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_32 = { #undef NUM_LAYER_0_UNITS_32 #undef NUM_LOGITS_32 -// BLOCK_16X16 #define NUM_HIDDEN_LAYERS_16 1 -#define NUM_FEATURES_16 19 -#define NUM_LAYER_0_UNITS_16 16 +#define NUM_FEATURES_16 25 +#define NUM_LAYER_0_UNITS_16 32 #define NUM_LOGITS_16 10 -static const float simple_motion_search_prune_part_logits_kernel_16[] = { - 0.274123f, -0.551439f, 0.578938f, -0.213001f, -0.310021f, - 0.0301311f, -0.377388f, -3.16339f, 0.434616f, 0.264216f, - 0.320385f, -1.41657f, 1.05919f, -0.396075f, -0.855458f, - 0.418105f, -0.0769093f, -0.54773f, -0.215041f, -0.13885f, - -0.209062f, -0.526914f, 0.211082f, -2.34741f, -0.000587922f, - -0.431294f, 0.757511f, -0.184199f, -0.623552f, -0.221362f, - -0.628871f, 0.646393f, -0.192193f, 0.0166809f, -0.061691f, - -0.214283f, -0.35264f, 0.361452f, -0.0160958f, -0.0475499f, - 0.196822f, 0.44674f, -0.408064f, -0.559148f, -0.67489f, - -0.202201f, -0.358012f, -0.341735f, -0.325682f, 0.220407f, - -0.642416f, 0.350069f, 0.430505f, -0.0997745f, -0.300435f, - 1.25364f, -0.869717f, -0.0728051f, -0.172433f, 0.385328f, - -2.13737f, 0.673629f, 0.580102f, -0.0745359f, -0.442542f, - -0.208393f, -0.44303f, 0.318855f, 0.0557663f, 0.268257f, - -0.0941132f, -4.52876f, -0.638897f, -0.907808f, 0.28328f, - 0.619328f, -1.64249f, 0.0241431f, -0.0880383f, 0.299287f, - -0.248316f, 0.039253f, -0.544645f, -0.141389f, 0.0185283f, - -1.01973f, -0.269349f, -4.88803f, -0.632892f, 0.181151f, - 0.193291f, 0.592713f, -1.71466f, 0.398923f, 0.00355734f, - 0.212158f, -0.949188f, 0.386679f, -0.243317f, -0.17458f, - 0.0576348f, 0.096034f, -0.282317f, -4.13556f, -0.516689f, - 0.169427f, -0.541422f, 0.529281f, -1.45161f, -0.0417835f, - 0.0174299f, -0.26404f, -0.105773f, 0.102701f, -0.65039f, - 0.308121f, -0.185395f, 0.273611f, -0.408464f, -6.09866f, - -0.512249f, 0.0668662f, -0.547454f, 0.62565f, -1.63952f, - 0.510116f, 0.127461f, -0.506263f, 0.113016f, -0.258605f, - -0.308066f, 0.0957733f, 0.059395f, -0.915338f, 0.499407f, - -10.3199f, -0.32224f, -0.677307f, 1.13218f, -0.0888689f, - -0.108029f, -0.156533f, -0.391431f, 0.576607f, -0.0833897f, - 0.536752f, -0.0832957f, -0.0957492f, -0.135149f, 0.423881f, - 0.317691f, -7.29755f, 0.104775f, 0.534134f, -0.797288f, - -0.386335f, -0.20785f, -0.0507494f, -0.338127f, -0.868801f +static const float av1_simple_motion_search_prune_part_logits_kernel_16[] = { + -0.520913f, 0.395611f, 0.0369091f, -0.318591f, -0.463252f, + 0.134992f, -0.43154f, -0.0739112f, -0.118817f, 0.476373f, + -0.281406f, 0.3413f, 0.456255f, 0.33307f, 0.2942f, + 0.1317f, 0.498113f, 1.95406f, -0.165726f, -0.219306f, + -0.302656f, -1.31157f, -0.433662f, 0.151716f, -0.214817f, + 0.504523f, -0.710049f, 0.359616f, -0.412695f, -0.103193f, + 0.341912f, 0.351378f, -0.181486f, 0.573862f, -0.0396254f, + -0.17855f, -0.276163f, 0.0367465f, -0.353905f, -0.204689f, + 0.309581f, -0.0439686f, -0.147855f, 0.152745f, 0.290871f, + 0.131049f, -0.27808f, -0.142997f, 0.207843f, -1.23074f, + -0.267714f, -0.336923f, 0.313781f, -0.61488f, -0.161984f, + 0.238059f, -0.0879942f, -0.085543f, -0.260156f, -0.13614f, + -0.242196f, 0.201216f, -0.248691f, 0.0936671f, -0.350522f, + -0.35002f, -0.156583f, -0.00579001f, 0.300578f, -0.341269f, + -0.290712f, 0.354802f, -0.31629f, 0.509107f, -0.236953f, + -0.0923519f, 0.544509f, -0.280991f, -0.017437f, -0.202721f, + -0.116388f, -0.7191f, 0.324586f, 0.254249f, 0.125505f, + 0.00658697f, -0.333322f, -0.126537f, -0.140004f, -0.0241202f, + -0.172466f, 0.210035f, -0.270833f, 0.0579044f, 0.0950352f, + -0.120382f, 0.063292f, -0.394925f, 0.482165f, 0.147753f, + 0.331465f, -0.187444f, 0.1083f, 0.414028f, 0.279238f, + -0.486889f, -0.674349f, -0.313656f, -0.131186f, -0.100662f, + 0.238191f, -1.19083f, -0.30667f, -2.4324f, 0.235311f, + 0.108605f, 1.67197f, 0.476157f, 0.30055f, 0.0839538f, + 0.408469f, -0.473517f, 0.560283f, -0.0188136f, 0.273824f, + -0.43707f, -0.0346978f, -0.438315f, -0.0196275f, -0.0567921f, + -0.220166f, 0.216175f, -0.0180461f, 0.0116429f, -0.0096949f, + -0.32613f, 0.176829f, -0.243563f, -0.240972f, -0.621819f, + -0.00619648f, -0.145525f, 0.124324f, -0.0306925f, 0.172208f, + -2.04631f, -0.200087f, -0.594135f, -0.352303f, -0.309826f, + 0.0922786f, -0.698371f, -0.0366823f, 0.0244036f, 0.338775f, + -0.115947f, 0.144971f, -0.0607037f, -0.762412f, 0.0125584f, + -0.262427f, -0.0830273f, -0.291252f, -0.176059f, -0.203983f, + 0.0871455f, -0.0894925f, 0.0426263f, -0.060001f, -0.542355f, + -0.407837f, -0.0419273f, 0.226608f, -0.114844f, 0.158733f, + -0.187237f, 0.113163f, -1.86337f, -0.367544f, -0.547048f, + -0.24192f, -0.226764f, 0.090912f, 0.819604f, 0.433766f, + -0.841657f, 0.446987f, -0.622761f, -0.0296385f, -0.130176f, + -0.0518136f, -0.640326f, -0.330107f, -0.137832f, -0.0119033f, + 0.39401f, 0.111331f, -0.141367f, -0.230289f, 0.171054f, + -0.924059f, -0.107317f, -0.347983f, 0.0261109f, 0.423002f, + -0.305817f, 0.247696f, 0.0436002f, 0.0305862f, -1.52448f, + -0.595587f, -0.155552f, -1.11949f, -0.513937f, 0.138347f, + -0.301487f, 0.352144f, -0.615801f, 0.0326701f, -0.215322f, + -0.0608176f, -0.416557f, -0.306073f, -0.441512f, -0.0569277f, + -0.709768f, -0.602527f, -0.311134f, 0.152471f, -0.255299f, + 0.354505f, 0.194464f, 0.0144251f, 0.110732f, -0.4452f, + -0.804814f, 0.205325f, -0.0957486f, 0.502684f, 0.09112f, + -0.533087f, -1.77979f, 0.556992f, -0.176157f, -0.642633f, + 0.11553f, -0.232561f, 0.161277f, -0.0631125f, -0.20759f, + 0.489253f, -0.067533f, 0.0231024f, -0.179831f, -0.272985f, + -0.390059f, 0.3089f, 0.185733f, -0.257065f, -0.508838f, + -0.550028f, 0.0665621f, -0.138288f, -0.413188f, 0.191193f, + -1.32969f, -0.431025f, 0.270242f, -0.340062f, 0.0817257f, + 0.0376051f, -0.18633f, 0.0828274f, 0.00670051f, -0.431295f, + -0.450316f, -0.173042f, -0.322248f, 0.370628f, 0.10019f, + 0.317293f, -0.266613f, 0.0752441f, -0.425656f, -0.112223f, + 0.557991f, -0.324368f, -0.195261f, -0.0526129f, -0.807472f, + -0.387466f, 0.192186f, 0.353213f, -0.120238f, 0.107686f, + 0.200678f, -0.75363f, 0.466857f, -0.282345f, -0.0849236f, + -0.0490695f, -0.00643182f, 0.123047f, -0.207805f, -0.130456f, + -1.09455f, 0.340973f, 0.334784f, 0.0706643f, -1.65681f, + -0.319952f, -0.198514f, -0.0787972f, 0.089524f, 0.0531034f, + -0.202705f, -0.0852339f, -0.62572f, -0.0734234f, -0.838088f }; -static const float simple_motion_search_prune_part_layer_0_kernel_16[] = { - -0.244782f, 0.00425059f, -0.337534f, -0.423125f, -0.349549f, - -0.00261207f, -0.0845866f, -0.259278f, -0.375872f, 0.00052185f, - -0.427483f, 0.175625f, -0.357737f, 0.129946f, 0.97588f, - 1.19281f, -0.51292f, -0.100629f, 1.04044f, 0.197375f, - -0.210977f, -0.20334f, 0.173408f, 0.431999f, 0.083979f, - -0.334416f, -0.171408f, 0.160035f, -0.0464933f, 0.164574f, - -0.162781f, 1.01648f, 0.624844f, -1.20372f, -0.698742f, - 0.335747f, -0.362217f, -0.0817772f, -0.0366522f, -0.249627f, - -0.3135f, 0.256151f, -0.257869f, 0.0816391f, -0.256592f, - 0.071219f, -0.295956f, 0.287213f, -0.375107f, -0.149275f, - 0.0449292f, 0.49489f, -0.958944f, 0.386166f, -0.76147f, - -0.223786f, 1.91139f, -0.0866129f, -0.516556f, 0.871813f, - 0.389086f, 0.3205f, 0.605997f, -0.531384f, -0.693121f, - 0.728219f, 0.223733f, -0.58534f, -0.410249f, 0.0271334f, - -0.43904f, 0.325998f, -0.123988f, 0.103988f, -0.2227f, - 0.0779071f, 0.100073f, -0.924956f, -0.00472742f, -0.21932f, - -0.220187f, -0.719278f, 0.099118f, -0.0891471f, 0.743678f, - -0.173308f, 0.588225f, -0.31524f, 1.1415f, 0.408762f, - -0.213088f, -0.291621f, 0.655754f, 0.531725f, -0.013178f, - -0.100753f, -0.0775942f, -0.181806f, -0.441297f, -0.00589338f, - 0.14217f, -0.0592671f, 0.10907f, 1.47619f, 0.813817f, - 0.1996f, 0.178263f, -0.569958f, -0.374858f, -0.743922f, - -0.269343f, -0.118752f, 0.0797114f, 0.027829f, -0.133402f, - -0.164884f, -0.42919f, 0.0682661f, -0.206438f, 0.0184534f, - -0.141316f, -0.138817f, 0.0305671f, 0.295578f, -0.236413f, - 0.172918f, -0.35082f, -0.0986917f, -0.650484f, 0.13655f, - 0.212195f, 0.549501f, 1.64941f, 0.152883f, 0.0117464f, - -0.200688f, -0.0412075f, -0.0296324f, 0.122624f, 0.1871f, - -0.515693f, 0.20351f, 0.333617f, 0.254752f, 0.293802f, - -0.428904f, -0.0312053f, -0.879481f, -0.516353f, -0.417837f, - -0.230442f, 0.229367f, 0.615339f, 0.327347f, 0.288747f, - 0.596166f, 0.497054f, 0.536953f, 0.462426f, 0.517022f, - -0.287359f, -0.162824f, -0.249174f, -0.364887f, -0.538065f, - -0.506783f, -0.163213f, -0.617007f, -0.70433f, -0.759151f, - -0.235183f, -0.196496f, 0.0925943f, -0.0786896f, 0.135073f, - -0.106243f, -0.190647f, -0.311848f, -0.428009f, 0.467477f, - 0.259139f, 1.4948f, 0.986061f, -0.534924f, -0.193525f, - -0.66125f, -0.693799f, -0.489594f, 0.238264f, 0.249978f, - -0.365372f, -0.197998f, -0.664471f, -0.0312145f, -0.297293f, - 0.0278792f, -0.877716f, 0.0473106f, 0.913044f, 0.815569f, - 0.789972f, 0.641374f, -0.122848f, -0.353137f, -0.381102f, - -0.960138f, -0.166101f, 0.230364f, 0.534173f, 0.398882f, - 0.0599076f, 0.00176035f, 0.291062f, 0.021087f, 0.374562f, - 0.402516f, 0.144006f, -0.149598f, 0.065063f, -0.0774656f, - -0.18804f, -0.21123f, 0.0119723f, -0.244286f, 0.109912f, - -0.98136f, -0.583136f, -1.3897f, 0.33196f, 0.319226f, - 0.490015f, 0.316438f, 0.565049f, 0.163159f, 0.523771f, - 0.325115f, -0.0515304f, -0.0827355f, 0.112763f, -0.517608f, - -0.161398f, -0.124513f, -0.0384277f, -0.49491f, -1.53384f, - -1.3086f, 1.20601f, 0.399591f, 0.233774f, 0.0154149f, - -0.431196f, 0.187116f, 0.033398f, 0.655468f, -0.390814f, - 0.418144f, -0.572053f, 0.936493f, -0.116933f, -0.20803f, - -0.908834f, 1.2524f, -0.285888f, 0.227437f, -0.317727f, - -0.6331f, 0.159656f, 0.244652f, 0.169768f, 0.379279f, - 0.37089f, 0.118264f, 0.150946f, 0.536513f, -0.261398f, - -0.15329f, -0.413112f, -0.243792f, -0.215096f, 0.288741f, - -0.193763f, -0.130652f, -0.328159f, -0.719996f, -1.66213f, - 0.0815627f, 0.129643f, -0.0974464f, -0.0660102f, 0.349602f, - 0.120356f, -0.144144f, -0.13641f, -0.154818f, -0.468552f, - -0.442585f, -0.312206f, 0.879662f, 0.846103f, 0.0485413f, - 0.18676f, -0.477959f, -0.112404f, -0.366477f +static const float av1_simple_motion_search_prune_part_layer_0_bias_16[] = { + -0.0616197f, 0.939947f, 0.521161f, 0.213886f, 0.130324f, -0.127443f, + -0.0538715f, 0.708746f, 0.445031f, 0.418781f, -0.114539f, 0.521941f, + 1.13719f, 0.606545f, -0.32193f, -0.150788f, 0.158487f, -0.224005f, + 0.654715f, 0.115729f, -0.286506f, -2.06223f, 0.0117697f, 0.503905f, + -0.102339f, 0.653256f, -0.813561f, 0.905235f, -0.417269f, -0.206265f, + 0.661496f, 0.95533f }; -static const float simple_motion_search_prune_part_logits_bias_16[] = { - 0.791815f, 0.888054f, 0.406071f, -0.217564f, -0.504713f, - -0.514339f, -0.200842f, -1.09239f, -1.78297f, -2.41754f +static const float av1_simple_motion_search_prune_part_layer_0_kernel_16[] = { + -0.203489f, 0.00686229f, -0.161414f, 0.0637276f, 0.27516f, + 0.512219f, 0.164205f, 0.00326062f, -0.41914f, -0.400334f, + 0.554419f, 0.715772f, -0.295569f, -0.703503f, 0.0137744f, + -0.0934259f, 0.174234f, -0.148618f, -0.0360558f, -0.0986598f, + -0.138502f, -0.0770713f, 0.122922f, -0.00784415f, 0.0953234f, + -0.255754f, -0.310967f, 0.185306f, 0.464554f, 0.147338f, + -0.0612304f, 0.164783f, 0.301097f, 0.161364f, -0.12723f, + -0.0265984f, -0.471361f, 0.0578776f, -0.362865f, 0.425789f, + 0.402758f, -0.190235f, 0.00549738f, -0.570908f, 1.27206f, + 0.048868f, -0.0097675f, 0.0708324f, 0.0456103f, 0.0149062f, + -0.563032f, -0.420573f, 0.107278f, 0.0938258f, 0.142712f, + -0.00251036f, -0.250583f, 0.522272f, 0.0113175f, 0.126751f, + -0.433028f, -0.035542f, -0.536686f, -0.0668722f, 0.253094f, + 0.254007f, -0.435505f, 0.343001f, 0.0531542f, -0.361914f, + -0.102664f, 0.0404874f, 0.132686f, 0.0762298f, 0.0236971f, + -0.419454f, 0.230877f, -0.223714f, 0.037813f, 0.0818604f, + 0.383705f, -0.235028f, -0.0554801f, 0.429851f, 0.0845829f, + 0.166295f, 0.355111f, -0.421197f, 0.298949f, 0.0218224f, + 0.445705f, -0.392217f, -0.429578f, -0.076276f, -0.0963531f, + -0.631425f, -0.225977f, 8.06349e-06f, 0.0676679f, 0.0779651f, + 0.0706891f, 0.101377f, 0.517103f, 0.0945502f, -0.52522f, + -0.312022f, 0.0358089f, 0.616509f, -0.0507444f, -0.465814f, + -0.0326024f, 0.591298f, 0.188544f, -0.0633316f, -0.199987f, + 0.403118f, -0.511281f, -0.696263f, 0.112996f, 0.103875f, + 0.0495595f, -0.0107449f, 0.521539f, -0.0123823f, -0.0642751f, + 0.08548f, -0.0679207f, 0.526558f, 0.0651114f, -0.342643f, + -0.349934f, 0.307437f, 0.368763f, -0.194851f, -0.134117f, + 0.102448f, -0.0520666f, 0.0415824f, -0.175085f, 0.272685f, + 0.0675856f, 0.120627f, 0.391408f, -0.135249f, -0.357024f, + 0.019666f, -0.0622677f, 0.407427f, 0.22655f, -0.129432f, + -0.165327f, 0.004893f, 0.5479f, 0.0613981f, -0.479682f, + -0.144228f, -0.130106f, 0.206458f, -0.342086f, 0.12691f, + -0.113554f, 0.231164f, -0.051419f, 0.0401286f, -0.560429f, + -0.070609f, 0.420232f, 0.442465f, -0.237501f, -0.000293732f, + -1.017f, -0.210222f, 0.0157063f, 0.0488178f, 0.0734721f, + -0.52626f, -0.276441f, -0.521579f, 0.443532f, -0.0819051f, + -0.0732633f, -0.17999f, 0.258525f, -0.0374872f, 0.150115f, + 0.0510939f, 0.168116f, 0.473372f, 0.824489f, 0.302195f, + -0.348613f, 0.238569f, 0.176444f, -0.633945f, -0.0567195f, + -0.0305827f, -0.0551851f, 0.85822f, -0.0628099f, 0.0364294f, + -0.234823f, 0.179067f, 0.143208f, -0.0511014f, -0.404191f, + 0.428035f, 0.0235506f, 0.371991f, -0.312909f, 0.550933f, + -0.389265f, -0.271813f, -0.293461f, -0.583752f, 0.179991f, + 0.191698f, 0.659094f, 1.07941f, -0.509555f, -0.100638f, + 0.079988f, -0.0519107f, -0.112723f, -0.0663326f, 0.0353569f, + -0.795055f, -0.465999f, 0.283579f, 0.340913f, 0.152738f, + 0.294664f, 0.527839f, 0.187735f, 0.359461f, 0.164629f, + 0.107512f, 0.390402f, 0.236702f, 0.114674f, -0.525655f, + -0.555476f, -0.6589f, -0.266601f, -0.0946547f, 0.6306f, + 0.0248513f, 0.038497f, 0.432706f, -0.0715465f, 0.0410172f, + -0.115313f, -0.428684f, 0.136283f, 0.0913185f, 0.11277f, + 0.0968689f, -0.00437052f, 0.0888981f, 0.10304f, 0.02442f, + -0.211315f, 0.00981596f, -0.0974827f, 0.208611f, 0.140644f, + 0.0315567f, 0.350332f, -0.291049f, -0.0715449f, -0.352992f, + -0.858004f, 0.828658f, 0.439092f, 0.0151291f, 0.0503828f, + 0.0656112f, -0.710749f, -0.0951757f, 0.193908f, 0.00908018f, + 0.141486f, -0.0657711f, 0.099791f, 0.153729f, -0.419576f, + -0.892636f, -0.0449268f, -0.170786f, -0.156564f, 0.384511f, + 0.296565f, 0.0569815f, -0.103938f, 1.27479f, -0.0406475f, + 0.154083f, -0.186442f, 0.0282588f, 0.0312102f, -0.188994f, + 0.284243f, -0.564693f, 0.425525f, -0.00924596f, 0.810003f, + 0.233812f, -0.0180273f, 0.121082f, -0.209096f, 0.151437f, + 0.286921f, -0.348095f, 0.174813f, -0.413798f, 0.108994f, + -0.34266f, -0.0337981f, -0.459f, -0.409812f, -0.0890104f, + 0.0834802f, -0.00259191f, -0.105914f, -0.164207f, 0.0697689f, + -0.312098f, -0.00650536f, -0.486758f, -0.248486f, 0.24314f, + -0.0857144f, 0.0884781f, -0.65615f, -0.121744f, 0.0709335f, + -0.0237193f, 0.10764f, -0.0409452f, -0.0824305f, 0.42329f, + 0.138258f, 0.502607f, 0.228545f, 0.0687789f, 0.0361586f, + 0.39074f, 0.0722654f, -0.0133148f, 0.283278f, 0.0743384f, + 0.310292f, -0.297675f, -0.359935f, 0.521021f, -0.10082f, + -0.272333f, 0.0120283f, 0.138118f, -0.123711f, -0.0711386f, + 0.0170747f, 0.831039f, 0.0509626f, 0.790608f, -0.0863406f, + -0.31962f, 0.0631013f, 0.0873453f, -0.472331f, -0.0826027f, + -0.241722f, 0.148835f, -0.131611f, 0.000195347f, -0.0615804f, + -0.838663f, -0.586979f, 0.247713f, 0.362254f, 0.492727f, + -0.132163f, 0.0516545f, 0.477838f, -0.0395182f, 0.0124993f, + -0.771514f, 0.0386912f, -0.118525f, -0.346172f, -0.265905f, + -0.175257f, -0.406287f, 0.393837f, 0.409096f, -0.408501f, + -0.0207146f, 0.0487809f, 0.0636982f, 0.0276368f, 0.0878249f, + 0.0425889f, 0.0868633f, 0.17423f, -0.128217f, -0.477068f, + -0.321294f, 0.0393771f, 0.00812823f, -0.350529f, -0.129012f, + 0.439953f, 0.396662f, 0.410475f, -0.123129f, -0.565966f, + 0.0298635f, -0.614611f, -0.477514f, 0.453651f, 0.0617068f, + 0.0530563f, 0.0479074f, 0.213551f, 0.039034f, 0.0449095f, + -1.06868f, -1.2654f, -0.175482f, 0.595068f, -0.230095f, + 0.719838f, -0.272148f, 0.696564f, 0.0485396f, 0.468584f, + 0.0695439f, -0.0842122f, -0.228978f, 0.161397f, -0.000441421f, + -0.0297514f, -0.250599f, 0.196656f, 0.608423f, -0.0112096f, + 0.0236881f, -0.00167311f, 0.0040709f, 0.015495f, 0.00757698f, + -0.165886f, 0.359767f, -0.0214696f, 0.377208f, 0.0303547f, + 0.0657094f, 0.140775f, 0.21867f, -0.203922f, 0.263878f, + -0.0529099f, 0.202438f, -0.243226f, 0.156659f, -0.627056f, + -0.845036f, -0.500873f, 0.172588f, 0.402972f, -0.147734f, + 0.151792f, -0.075579f, 0.443519f, 0.0311335f, -0.0328222f, + -0.0299781f, 0.435956f, -0.0987376f, 0.288402f, 0.135902f, + -0.173584f, -0.186255f, 0.224524f, -0.249645f, 0.123702f, + -0.0846244f, 0.491317f, 0.544846f, 0.338677f, -0.258885f, + -0.617434f, -0.629003f, -0.347233f, 0.181262f, -0.0606015f, + -0.537766f, 0.215089f, -0.334527f, 0.0488534f, 0.0577997f, + -1.12431f, -0.932292f, -0.11559f, 0.573715f, 0.151128f, + 0.693818f, -0.16956f, 0.802591f, -0.231531f, 1.04318f, + -0.476417f, 0.293452f, -0.610136f, 0.27506f, -0.384012f, + 0.305366f, -0.0540464f, -0.337583f, -0.174285f, 0.157248f, + 0.0477345f, -0.0229535f, 0.0475766f, -0.00603319f, 0.00856119f, + -0.702893f, -0.0579673f, 0.183024f, -0.166222f, 0.109763f, + -0.148019f, -0.258873f, -0.0820157f, -0.186716f, -0.449265f, + -0.0534138f, 0.15732f, 0.46357f, 0.00502591f, -0.0282085f, + 0.152277f, -0.855199f, -0.357115f, 0.0366159f, 0.0131101f, + -0.0407758f, 0.0462835f, 0.146309f, -0.00276278f, -0.0591814f, + -0.109437f, 0.506764f, -0.044421f, 0.465907f, 0.114444f, + -0.241053f, -0.362649f, -0.432615f, 0.199989f, -0.00635866f, + -0.521886f, 0.0958924f, -0.485725f, 0.0430527f, 0.069746f, + 0.681091f, -0.288144f, 0.505671f, 0.0489065f, -0.0373836f, + 0.266079f, 0.145173f, -0.011481f, -0.225074f, -0.754501f, + -0.122939f, -0.294213f, 0.334738f, 0.281561f, 0.558977f, + -0.21551f, -0.346507f, -0.0625635f, 0.0782034f, -0.236999f, + -0.803783f, -0.601117f, 0.091192f, 0.636122f, -0.250626f, + 0.0354961f, 0.103915f, 0.508571f, 0.329911f, -0.0425999f, + -0.0867587f, -0.0385824f, 1.13914f, -0.0261992f, 0.00484478f, + 0.124603f, -0.012173f, -0.377358f, -0.243563f, 0.236094f, + 0.145663f, -0.132752f, 0.347497f, -0.529315f, 0.271632f, + -0.372805f, 0.0261836f, 0.126169f, 0.0941008f, 0.283773f, + 0.765701f, -0.226477f, -0.181549f, -0.306896f, 0.110165f, + -0.0784234f, -0.0827892f, -0.0374252f, -0.0950872f, -0.451015f, + -0.995793f, -0.452663f, 0.293338f, -0.380865f, 0.032683f, + 0.0178248f, 0.0699194f, -0.0811722f, -0.0866096f, 0.139289f, + 0.296604f, 0.192293f, -0.0589607f, -0.179878f, 0.00360266f, + -0.0905794f, 0.136744f, -0.191555f, 1.31877f, -0.0592033f, + -0.158766f, 0.0214746f, -0.190113f, -0.116671f, 0.0449292f, + -0.109533f, -0.709307f, 0.386424f, 0.40201f, 0.262211f, + -0.155244f, 0.233988f, -0.0166317f, 0.462665f, 0.0484462f, + 0.210902f, -0.352798f, 0.38698f, -0.228261f, -0.084309f, + -0.220751f, -0.170879f, -0.352617f, -1.24277f, 0.266004f, + -0.0125749f, -0.0380073f, 0.101838f, -0.0483024f, -0.0629178f, + -0.0695577f, -0.103439f, 0.242131f, -0.0796858f, 0.349718f, + -0.332045f, 0.0138352f, -0.380235f, -0.28717f, -0.176276f, + 0.865903f, 0.36593f, 0.243925f, -0.422289f, -0.117327f, + 0.21876f, 0.245393f, -0.426134f, -0.186077f, 0.0352515f, + -0.123742f, 0.249376f, 1.3281f, 0.0707771f, 0.071415f, + -0.286827f, -0.131691f, -0.270881f, -0.434378f, 0.376064f, + 0.35966f, 0.513374f, 0.439378f, -0.222716f, -0.5874f, + 0.487997f, -0.293271f, -0.184245f, -0.037256f, 0.17723f, + -0.438651f, 0.428184f, 0.112983f, -0.449287f, -0.0451963f, + 0.0854929f, 0.0735442f, -0.0148642f, -0.0586782f, -0.176455f, + -0.438979f, -0.127109f, 0.211478f, 0.388035f, -0.0372021f, + 0.220575f, 0.382144f, 0.302121f, 0.0857121f, 0.193445f, + -0.488858f, -0.195288f, -0.316184f, -0.314026f, -0.111956f, + 0.0744768f, 0.292709f, 0.30187f, -0.285506f, -0.105006f, + 0.0851402f, -0.082318f, 0.277518f, 0.725294f, -0.756304f, + 0.0155309f, -0.378542f, 0.293377f, -0.347252f, -0.338458f, + 0.221449f, -0.176443f, -0.131972f, 0.0129163f, -0.290649f, + 0.198596f, -0.0721333f, 0.620591f, 0.568736f, 0.174001f, + -0.205186f, -0.265606f, -0.249155f, 0.299163f, 1.11842f, + 0.17423f, 0.196417f, -0.014484f, 0.0735422f, 0.26329f, + 0.12284f, -0.750305f, -0.351337f, 0.121994f, -0.00542878f, + -0.295707f, -0.094124f, 0.300993f, 0.412408f, -0.170761f, + -0.0676329f, -0.106638f, -0.419785f, -0.43878f, 0.22421f, + 0.0339903f, 0.619851f, 0.0615381f, 0.514631f, 1.35424f, + -0.0679228f, -0.203457f, 0.131948f, -0.0041251f, -0.209054f }; -static const float simple_motion_search_prune_part_layer_0_bias_16[] = { - 0.89469f, 0.10871f, 0.664404f, -0.00639695f, -0.745647f, 0.910444f, - 0.168436f, -4.05854f, 1.00981f, 0.743352f, -0.73947f, -2.5654f, - -0.654753f, 0.602252f, -0.973004f, 1.1113f +static const float av1_simple_motion_search_prune_part_logits_bias_16[] = { + 0.304025f, 0.131887f, 0.259279f, -0.561564f, -0.161729f, + -0.208036f, 0.102206f, -0.162937f, -1.42311f, -0.708305f }; -static const NN_CONFIG simple_motion_search_prune_part_nn_config_16 = { +static const NN_CONFIG av1_simple_motion_search_prune_part_nn_config_16 = { NUM_FEATURES_16, NUM_LOGITS_16, NUM_HIDDEN_LAYERS_16, @@ -3617,12 +3739,12 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_16 = { NUM_LAYER_0_UNITS_16, }, { - simple_motion_search_prune_part_layer_0_kernel_16, - simple_motion_search_prune_part_logits_kernel_16, + av1_simple_motion_search_prune_part_layer_0_kernel_16, + av1_simple_motion_search_prune_part_logits_kernel_16, }, { - simple_motion_search_prune_part_layer_0_bias_16, - simple_motion_search_prune_part_logits_bias_16, + av1_simple_motion_search_prune_part_layer_0_bias_16, + av1_simple_motion_search_prune_part_logits_bias_16, }, }; @@ -3631,138 +3753,213 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_16 = { #undef NUM_LAYER_0_UNITS_16 #undef NUM_LOGITS_16 -// BLOCK_8X8 #define NUM_HIDDEN_LAYERS_8 1 -#define NUM_FEATURES_8 19 -#define NUM_LAYER_0_UNITS_8 24 +#define NUM_FEATURES_8 25 +#define NUM_LAYER_0_UNITS_8 32 #define NUM_LOGITS_8 4 -static const float simple_motion_search_prune_part_logits_kernel_8[] = { - -0.806717f, 0.0244927f, -0.0280725f, 0.210426f, 0.0820434f, -0.0222324f, - -0.0728984f, -0.424785f, -0.0568035f, -0.0744017f, 0.204282f, 0.43611f, - 0.319456f, 0.119903f, -0.333224f, -0.932499f, 0.105907f, 0.0905287f, - -0.612538f, 0.0978191f, -0.0858663f, 0.0468925f, -0.312509f, 0.0527469f, - 0.308466f, -0.139768f, -0.468023f, -0.069522f, 0.248949f, 0.0408582f, - 0.199935f, -0.448705f, 0.242315f, 0.00472276f, -0.468445f, -0.591226f, - 0.107975f, 0.261228f, -0.10724f, 0.104639f, -0.211234f, -0.304658f, - -0.261689f, -0.259529f, 0.0331369f, -0.468468f, -0.0555605f, -0.0495414f, - 0.247612f, -0.112518f, -0.393122f, 0.302172f, -0.252151f, 0.076605f, - -0.34155f, -0.182731f, 0.154079f, -0.464538f, -0.396327f, -0.654858f, - 0.0921198f, 0.202867f, -0.0712573f, 0.0349611f, 0.243043f, -0.177452f, - -0.205536f, -0.268024f, 0.0358315f, -0.560347f, -0.204207f, -0.0890628f, - -1.013f, -0.461748f, -0.429801f, -0.100352f, -0.34369f, 0.115318f, - -0.556285f, -0.0751575f, 0.183418f, -0.285223f, 0.197177f, -0.825216f, - -0.125709f, -0.100452f, 0.180481f, 0.764462f, 0.136609f, -0.660743f, - 0.212887f, -0.410408f, -0.330839f, -0.714646f, -0.115863f, -0.389509f +static const float av1_simple_motion_search_prune_part_logits_kernel_8[] = { + -0.266303f, -0.387676f, 0.204501f, -0.120842f, -0.0752326f, 0.0337739f, + 0.0243477f, -0.356748f, 0.0143051f, -0.16403f, -0.139013f, 0.175003f, + -0.206754f, 0.349059f, 0.181763f, 0.212768f, -0.313783f, 0.182829f, + 0.00205376f, -0.939525f, -0.0992424f, 0.306254f, 0.083329f, -0.133137f, + -0.179022f, -0.0237902f, 0.0601026f, -0.216698f, -0.551149f, 0.081711f, + -0.442191f, 0.0680832f, -0.0353678f, 0.237704f, 0.23155f, -0.36097f, + 0.123389f, -0.288927f, 0.178133f, -0.152222f, -0.235648f, -0.0495293f, + -0.316522f, 0.034207f, 0.0463139f, -0.817825f, 0.417443f, -0.110984f, + -0.402371f, 0.0341694f, -0.37383f, 0.414532f, 0.093993f, 0.0039505f, + 0.0803175f, -0.511859f, -0.0154802f, 0.0979595f, 0.0909049f, -0.120938f, + -0.577382f, -0.155041f, -0.404295f, 0.122223f, -0.084703f, 0.00415336f, + 0.149135f, 0.113219f, 0.124236f, -0.240905f, 0.163909f, -0.154202f, + -0.208917f, 0.00200158f, -0.71796f, 0.105984f, -0.131996f, -0.539603f, + 0.223768f, -0.0710733f, -0.346679f, -0.0745909f, 0.171032f, 0.215701f, + 0.218519f, 0.105981f, -0.096209f, -0.166453f, -0.468894f, -0.401578f, + -0.239222f, 0.111382f, 0.38747f, -0.164734f, -0.175955f, 0.336621f, + -0.0305501f, -0.0576765f, 0.0672671f, -0.183692f, 0.412082f, -0.262951f, + -0.153429f, -0.128589f, -0.530472f, 0.0936412f, -1.08296f, -0.45147f, + 0.0714904f, -3.96842f, 0.438125f, -0.313945f, 0.231104f, -0.00183851f, + -0.0192768f, -0.637531f, -0.109296f, 0.0531702f, 0.00262162f, -0.615951f, + -0.546241f, -0.635305f, -0.0762367f, 0.0122019f, 0.423693f, -0.129142f, + -0.112242f, 0.295184f }; -static const float simple_motion_search_prune_part_layer_0_kernel_8[] = { - 0.0561017f, 0.530692f, 0.129047f, 0.296138f, 0.407593f, - 0.151159f, 0.180472f, 0.298995f, -0.0265362f, -0.380313f, - -0.136716f, -0.0644648f, 0.00808564f, 0.0875876f, -0.0719683f, - -0.0996071f, -1.49722f, -1.31176f, 1.54169f, -0.50717f, - -0.0186767f, -0.525924f, 0.0402954f, -0.553913f, 0.139015f, - 0.171752f, -0.376497f, 0.485084f, 0.182424f, -0.0236465f, - 0.380048f, -0.185493f, 0.554435f, 0.241565f, -0.225917f, - -1.08637f, -0.305121f, 1.3603f, 0.0806333f, -0.0697466f, - 0.216192f, 0.0493694f, 0.0620039f, -0.0042489f, 0.0707283f, - 0.0998331f, -0.0252022f, 0.342077f, -0.200664f, 0.335261f, - -0.100772f, 0.212881f, -0.374258f, 0.310442f, -1.95981f, - -1.16615f, 1.88243f, 0.503536f, -0.0919037f, 0.392323f, - 0.33149f, 0.563121f, -0.0898854f, 0.130267f, 0.404959f, - 1.06767f, 0.75134f, 0.810919f, 0.865237f, -1.08001f, - -0.949809f, -1.24941f, -0.95081f, -0.539575f, -0.355324f, - -0.110592f, -0.311277f, 0.023022f, -0.039287f, 0.491298f, - -0.248853f, -0.294741f, 0.288811f, 0.470638f, 0.330094f, - 0.146603f, 0.0958486f, 0.308326f, -0.87134f, -1.06074f, - -0.315428f, 0.717577f, -0.0174599f, -0.491904f, 0.977014f, - 0.922693f, 0.0265707f, -0.743468f, -0.273647f, -0.430625f, - -0.473789f, 0.119983f, 0.476441f, 0.639803f, -0.0753475f, - -0.0746323f, -0.0422539f, 0.013454f, -0.0174412f, -0.253015f, - -0.279585f, 0.11562f, -0.396919f, 0.306388f, 0.430346f, - 0.275945f, -0.196508f, 0.00180146f, 0.396652f, 0.324022f, - -0.142132f, 0.1768f, -0.0746152f, 0.314189f, -0.031924f, - 0.254196f, -0.253449f, 0.1537f, -0.98635f, -0.850926f, - 0.0762147f, -0.652507f, 1.16528f, -0.122595f, -0.00561333f, - 0.424954f, -0.00258127f, -0.421957f, -0.0714059f, 0.782031f, - -0.0129133f, -0.00544328f, -0.193527f, -0.0936037f, -0.00490983f, - -0.852396f, -0.649662f, 0.820325f, 0.484966f, 0.265405f, - -0.33032f, 0.104917f, -0.364478f, 0.26858f, 0.068847f, - -0.0751046f, 0.238931f, -0.151554f, 0.0296385f, -0.14869f, - -0.173547f, -0.397285f, 0.0561029f, -0.0681254f, 0.222631f, - -0.00800993f, 0.0686761f, 0.196754f, 0.249358f, 0.348125f, - -2.22757f, 0.186675f, -0.0426998f, 0.123301f, -0.0196412f, - 0.104882f, 0.138482f, 0.340663f, 0.0684671f, -1.22841f, - -1.08539f, -1.1055f, -0.732678f, 0.766626f, 0.727742f, - 1.26906f, 0.812594f, -0.446312f, -0.166752f, 0.396628f, - 0.00141587f, 0.0137288f, -0.0920456f, 0.123027f, -0.118517f, - -0.0412321f, -0.124952f, 0.00875945f, 0.0149883f, -0.0218859f, - -0.233299f, -0.0812722f, 0.269917f, 0.0246593f, 0.0915655f, - -0.019122f, 0.706718f, -0.172051f, -1.85551f, 0.0578997f, - 0.100269f, 0.131412f, -0.0952751f, 0.181419f, -0.0106305f, - 0.106179f, -0.142344f, 0.0916649f, -0.41298f, 0.113846f, - -0.322459f, 0.0415754f, -0.2205f, -0.224231f, 0.147907f, - -0.135093f, -0.398757f, 1.93381f, 0.20456f, -0.205381f, - -0.263999f, 0.364463f, -0.424052f, -0.0166924f, -0.319968f, - 0.0439144f, -0.692733f, 0.678982f, -0.445194f, -0.527451f, - 0.383248f, 0.330927f, -0.0367725f, 0.572847f, -0.620804f, - -0.286471f, 1.39367f, 0.470732f, 0.0751676f, 0.637958f, - 0.574865f, 0.411091f, 0.263806f, 0.555064f, 0.047788f, - 0.201792f, -0.0821822f, -0.0226181f, -0.176679f, -0.612642f, - -0.992254f, -0.292099f, -0.562201f, -0.567948f, -0.767681f, - 1.33645f, 0.0932564f, -0.421675f, 0.198262f, -0.401979f, - 0.244609f, -0.261484f, 0.0304534f, -0.200004f, 0.00951232f, - -0.085364f, 0.555152f, -0.243778f, 0.371369f, 0.152997f, - 0.154443f, -0.281229f, 0.967176f, 1.0212f, 0.276169f, - 0.0962747f, 0.449737f, 0.300859f, 0.376659f, 0.165669f, - 0.332263f, 0.238315f, 0.376668f, -0.139238f, -0.0694765f, - -0.256137f, -0.262146f, -0.246265f, 0.0261978f, -0.118975f, - -0.207184f, -0.614041f, -0.866987f, -1.75604f, -0.04917f, - 0.0794673f, -0.355224f, 0.0035685f, -0.340216f, 0.398567f, - -0.314826f, -0.12464f, 0.693428f, 0.701697f, 0.511653f, - 0.861303f, -0.64449f, -1.06257f, -0.773944f, -0.838084f, - 0.802429f, -0.24573f, 0.720913f, -0.31002f, 0.615694f, - 0.287994f, 0.18495f, 0.0188525f, 0.374338f, -0.12243f, - 0.613532f, 0.132456f, 0.177285f, -0.187238f, 0.0872563f, - -0.425068f, 0.154711f, -0.24283f, -0.193267f, -1.14008f, - -1.17759f, 0.517845f, 0.458782f, -0.161137f, 0.142772f, - 0.2811f, 0.171871f, 0.276129f, 0.018275f, 0.390464f, - -0.156414f, 0.108248f, -0.0909085f, -0.11346f, 0.0815138f, - 0.0729377f, -0.0769677f, 0.0110251f, -0.46098f, -0.421538f, - -2.18003f, 0.6639f, 0.541278f, 0.704337f, 0.480695f, - 0.727474f, 0.473937f, 0.770863f, 0.41774f, -0.112943f, - -0.107412f, 0.083639f, -0.351127f, -0.149221f, 0.0705735f, - -0.0908294f, -0.0789572f, -1.62533f, -2.14051f, -0.188871f, - 0.796224f, 0.00144302f, 0.467569f, -0.113915f, 0.660595f, - 0.101025f, 0.020895f, 0.604505f, -0.26598f, -0.149282f, - -0.548818f, -0.140463f, 0.13669f, -0.0955724f, -0.694851f, - -0.13438f, -0.384164f, -0.600513f, 1.48183f, 0.16481f, - 0.340894f, -0.190813f, 0.487458f, 0.0769957f, 0.192901f, - 0.039483f, 0.213366f, -0.508968f, -0.494034f, -0.987906f, - -0.188502f, -0.907188f, 0.0109838f, -0.275008f, -0.331017f, - -0.447202f, 0.0521897f, 0.837215f, 0.344802f, 0.216526f, - 0.456105f, 0.139706f, -0.373955f, 0.0232853f, -0.365632f, - -0.0586727f, 0.828841f, 0.737974f, -0.933899f, -0.0620807f, - -0.262087f, -0.0551274f, -0.374378f, 0.118385f, -0.0375933f, - -0.39549f, -0.0844191f, 0.274343f, 0.21814f, 0.52751f, - 0.449546f, 0.075518f, 0.369501f, 0.345248f, 0.403972f, - -0.465168f, -0.551238f, -0.354305f, -0.233872f, 0.664137f, - -0.214848f, -0.0363864f, 0.446154f, -0.500073f, -1.07883f, - -1.07772f +static const float av1_simple_motion_search_prune_part_layer_0_bias_8[] = { + -2.16023f, -3.12831f, -0.213206f, -2.97875f, -1.83791f, -2.84713f, + -0.909636f, -2.05893f, 0.00525274f, -1.51672f, -3.95017f, 1.82847f, + -0.853224f, -3.29503f, -0.537517f, 0.923106f, -3.18665f, -1.29905f, + 1.64506f, -1.99848f, -2.24315f, 0.408613f, 0.503671f, -3.83393f, + -2.88388f, -3.52337f, 1.46818f, -1.67169f, -3.83253f, 1.52644f, + -0.490783f, -0.415782f }; -static const float simple_motion_search_prune_part_logits_bias_8[] = { - 1.09425f, -0.345875f, -0.56098f, -1.84859f +static const float av1_simple_motion_search_prune_part_layer_0_kernel_8[] = { + -0.702198f, -0.102148f, 0.0564545f, -0.0555548f, 0.16184f, + 0.0950792f, 0.136974f, -0.00824146f, 0.05746f, 0.0447542f, + 0.145978f, 0.0855769f, -0.041449f, 0.301347f, -0.0206691f, + -0.0662514f, -0.0525079f, -0.0998387f, -0.0891438f, 0.110545f, + -0.863098f, -1.83798f, 0.238818f, 0.127797f, 0.116872f, + -0.270655f, -0.21057f, 0.197013f, -0.123332f, 0.137104f, + -0.174766f, -0.00803025f, 0.0234369f, -0.0894175f, -0.0380927f, + 0.00827928f, -0.134148f, 0.110575f, -0.250173f, 0.116273f, + 0.0197749f, 0.270391f, 0.108437f, 0.173197f, -0.0650348f, + 0.0884626f, 0.262792f, 0.0649228f, 0.5573f, -2.81315f, + -0.479801f, -1.15825f, 0.0807932f, -0.19144f, 0.404016f, + -0.211521f, 0.233269f, -0.391414f, 0.160381f, -0.277233f, + 0.426354f, 0.156839f, 0.494315f, -0.214259f, -0.0132062f, + 0.148628f, -0.0899568f, 0.161845f, 0.467689f, 0.229474f, + 0.590634f, -0.705793f, -0.0486113f, -0.439088f, 0.994566f, + 0.679065f, 0.777869f, -0.225291f, -0.0303006f, -0.638782f, + -0.0824632f, -0.128561f, -0.327603f, 0.105624f, 0.567581f, + -0.396135f, -0.471028f, 0.181286f, 0.274604f, 0.180169f, + 0.0612144f, -0.865004f, 0.0306804f, 0.142985f, -0.0914358f, + -0.243284f, 0.358359f, -0.443847f, -0.371978f, 0.606933f, + -0.900408f, -0.52076f, 0.472118f, 0.0610973f, 0.152526f, + -0.550379f, 0.309331f, -0.141573f, 0.203046f, -0.231485f, + 0.505156f, 0.393224f, 0.435487f, -0.218681f, 0.123707f, + -0.270383f, -0.033565f, 0.210373f, -2.33967f, 0.367434f, + 0.0308118f, -0.205771f, 0.546141f, 0.19837f, 0.035648f, + -0.467007f, -1.50995f, -0.0314176f, 0.11762f, -0.15307f, + 0.618257f, -0.139502f, 0.303386f, -0.00758681f, 0.228107f, + -0.594499f, -0.201984f, -0.239666f, 0.114878f, -0.922174f, + -0.530137f, -0.379366f, -0.319582f, 0.0889624f, -0.00544663f, + 0.316264f, -0.204262f, -0.0959358f, 0.23552f, 0.141369f, + -0.207129f, -1.04067f, -0.0780501f, 0.226768f, -0.246752f, + 0.0823105f, 0.114783f, 0.49315f, 0.0197732f, 0.705433f, + 0.158076f, -0.250584f, -0.157326f, -0.0439547f, -0.139047f, + 0.090531f, -0.38833f, 0.743143f, -1.47418f, -0.155009f, + 0.511466f, -0.726716f, -0.181075f, 0.450133f, -0.390204f, + 0.292725f, 0.00811462f, -0.347738f, 0.613381f, -0.237124f, + 0.750748f, -0.383123f, 0.410309f, -0.204166f, 0.667199f, + -0.313197f, 0.436059f, -0.607571f, 0.193681f, 0.409399f, + 0.631747f, -0.0454149f, 0.198232f, 0.345591f, -0.0137374f, + -0.307014f, -0.535515f, 0.764678f, -0.225686f, -0.451621f, + -2.75564f, -1.52877f, 0.0511933f, 0.905979f, 0.145029f, + 0.759615f, 0.130166f, 0.83827f, 0.0655081f, 1.07555f, + -0.529777f, 0.682967f, -0.412052f, 0.611947f, -0.83676f, + 0.940695f, -0.465681f, 0.51505f, -0.883659f, -0.105524f, + -0.0344173f, -0.0683618f, -0.00698688f, -0.139349f, 0.135741f, + -0.294455f, -0.377834f, -0.602084f, -1.00128f, 0.483291f, + 1.25327f, 0.178987f, 0.75068f, -0.520731f, -0.325517f, + 0.272032f, 0.144144f, -0.279453f, 0.564907f, 0.144036f, + 0.297448f, -0.504243f, -0.250508f, -1.26395f, 0.4816f, + 0.392771f, -0.389961f, -0.261585f, -0.127124f, -0.202945f, + -0.709716f, -0.174719f, 0.113613f, 0.477753f, -0.226659f, + 0.0697828f, -0.177994f, 0.300726f, -0.185504f, 0.339424f, + -0.316746f, 0.369693f, -0.339723f, -0.143886f, -0.0326589f, + -0.268761f, -0.241094f, 0.284876f, -0.0270867f, -0.207397f, + -1.42738f, 0.495612f, -0.0277732f, 0.199675f, 1.48638f, + -0.659257f, -1.28199f, 0.498702f, 0.140695f, 0.571152f, + 0.416368f, 0.14153f, 0.126876f, 0.521114f, -0.00150571f, + 0.375581f, 0.00537624f, 0.1286f, -0.332227f, 0.417663f, + -0.539023f, 0.217124f, -0.787111f, -0.0335266f, 1.56751f, + 0.0640563f, -0.158791f, 0.118195f, 0.000970493f, -0.0403852f, + -0.0572557f, -0.0201181f, -0.10255f, 0.63237f, 0.156662f, + 0.418696f, -0.274802f, -0.663923f, -0.375232f, -0.40846f, + 0.462092f, 1.2176f, -0.301532f, -0.779704f, -0.112876f, + 0.0806591f, -0.0141923f, 0.00960801f, -0.663557f, 0.0979948f, + -0.0575999f, -0.012847f, 0.0403853f, -0.133666f, -0.00330217f, + -0.931518f, -0.774599f, -0.21391f, 0.377601f, -0.183365f, + 0.299094f, 0.0238552f, 0.206716f, -0.18959f, 0.346013f, + -0.150991f, -0.192817f, -0.293962f, -0.0537604f, -0.0648171f, + -0.275941f, -0.144854f, -0.224092f, 2.43113f, 0.0422494f, + -0.047236f, -0.0262028f, 0.0282119f, -0.175553f, 0.0888502f, + 0.580682f, 0.951055f, -0.284441f, -0.120133f, -0.268058f, + -0.312083f, -0.411556f, 0.21431f, -0.28033f, 0.324851f, + -1.02787f, -0.936816f, -0.577628f, 0.544743f, 0.295807f, + 0.406157f, 0.447927f, 0.25369f, -0.811421f, -0.0424979f, + -0.189867f, 0.00778673f, -0.113587f, -0.116175f, -0.0542222f, + -1.80089f, -1.44175f, -0.35332f, 0.191314f, -0.236691f, + -0.0261926f, -0.502363f, 0.252278f, -0.485478f, 0.296495f, + 0.455612f, -0.0489631f, 0.227255f, 0.170975f, 0.473487f, + 0.257812f, 0.178048f, 0.2506f, 2.04637f, -0.173857f, + 0.0583379f, 0.00765589f, -0.025772f, -0.162666f, -0.016214f, + -0.607486f, -0.0808025f, 0.0551611f, -0.0772291f, 0.126421f, + 0.10869f, -0.0877463f, -0.111527f, -0.0775766f, 0.503886f, + -0.002757f, -0.0421354f, -0.247857f, 0.140827f, 0.383576f, + 0.228232f, -0.157877f, -0.0927911f, 0.344687f, 0.191181f, + 0.236533f, 0.00102869f, -0.0184502f, -1.4509f, -1.15945f, + -0.521978f, -0.643225f, 0.133139f, 0.0660321f, 0.0851957f, + 0.0303648f, 0.0296239f, 0.0455713f, 0.175647f, 0.080532f, + 0.0445691f, -0.257356f, -0.125602f, -0.138829f, -0.167057f, + -0.0992552f, -0.13944f, 0.507531f, 0.444997f, 0.221452f, + -0.308384f, -0.327554f, 0.13235f, 2.1487f, -1.15453f, + -0.280239f, -0.363582f, -0.00358745f, 0.012866f, 0.251088f, + 0.0676416f, 0.178492f, -0.136631f, 0.197938f, -0.078198f, + 0.812439f, 1.1173f, 0.712113f, 1.10124f, -0.836503f, + -1.22433f, -1.07894f, -1.29215f, 0.56057f, 2.23928f, + -0.419029f, 0.282178f, -0.0719266f, -0.172192f, 0.28034f, + -2.99124f, -2.01481f, 0.0688982f, 0.697466f, 0.00635555f, + 0.566069f, 0.047534f, 0.507755f, -0.00690707f, 0.712594f, + -0.191467f, 0.355733f, -0.480016f, 0.664669f, -0.390619f, + 0.351199f, -0.482342f, 0.325005f, 1.9089f, 0.155987f, + 0.17032f, 0.132729f, 0.0402649f, 0.146991f, 0.0314905f, + -0.775316f, -0.208892f, -0.105993f, 0.0181653f, -0.12735f, + 0.0897852f, 0.0470231f, 0.25807f, 0.127406f, -0.0893252f, + -0.279776f, 0.190844f, 0.110384f, -0.148833f, 0.025293f, + 0.239838f, 0.00932245f, 0.35103f, -0.128268f, -0.0536754f, + 0.506899f, -0.16793f, 0.0955582f, -2.01108f, 0.721433f, + -2.31413f, -2.08646f, 0.033315f, 0.689828f, -0.271213f, + 0.790425f, -0.114234f, 0.755325f, -0.211533f, 0.774544f, + -0.263268f, 0.795762f, -0.551455f, 0.953602f, -0.168454f, + 0.529055f, -0.768991f, 0.882371f, 0.29763f, -0.155017f, + 0.00464101f, 0.121093f, 0.948271f, 0.113138f, -0.110332f, + -2.0492f, -1.31322f, -0.129212f, 0.464778f, -0.181465f, + 0.618403f, 0.0627984f, 0.465228f, 0.165729f, 0.278277f, + -0.563276f, -0.358358f, -0.590638f, 0.0104993f, 0.731206f, + 0.752569f, 0.631615f, 0.811822f, 0.129804f, -0.0558327f, + 0.570081f, -0.417922f, -0.168275f, 0.0703671f, 0.269127f, + 0.240457f, -0.197159f, -0.00179261f, 0.220065f, 0.463511f, + 0.0714626f, -0.716477f, -0.441865f, -0.717028f, -0.149176f, + 0.452182f, 0.662699f, -0.906534f, -0.817133f, 0.237747f, + 0.26024f, -7.7441e-05f, 0.0934616f, 0.824641f, -0.0404494f, + -0.088297f, -0.157899f, 0.037408f, 0.132435f, -0.316155f, + -0.276785f, 0.0117868f, 0.185008f, 0.32369f, -0.465855f, + -0.302127f, 0.303289f, 0.338597f, -0.665408f, -0.507594f, + 0.526979f, 0.532091f, 0.234395f, 0.754063f, 0.116769f, + 0.0800309f, -0.939344f, -1.51269f, 1.4583f, 0.178444f, + 0.0106756f, -0.213468f, -0.00369439f, 0.071015f, -0.192798f, + -0.0933147f, -0.129901f, -0.368279f, -0.246564f, 0.126966f, + 0.478565f, -0.476246f, -0.762863f, 0.168883f, 0.536136f, + -0.272969f, 0.2573f, -0.161577f, 0.311428f, -0.777994f, + -1.29752f, 0.216046f, 0.329016f, 1.57265f, 0.168075f, + -0.192518f, 0.0829308f, -0.073533f, -0.0202034f, 0.114716f, + -0.34888f, -0.519215f, 0.190809f, 0.0138507f, 0.133635f, + 0.14194f, 0.410618f, -0.165106f, 0.214438f, 0.0438265f, + -0.8481f, -1.19182f, -1.07878f, -0.882217f, 0.45616f, + 0.977385f, 0.74929f, 0.918466f, 0.904704f, 0.041938f, + 0.0362776f, 0.0757255f, 1.14007f, 0.0516825f, -0.160068f, + 0.219535f, 0.638634f, -0.0284544f, -0.222849f, -0.0344915f, + -0.0350256f, -0.0504452f, -0.0458416f, 0.146099f, 0.0783083f, + 0.206579f, 0.241264f, 0.28401f, 0.0425312f, -0.802049f, + -0.746271f, -0.578969f, -0.078218f, 0.436176f, -0.281465f, + -2.5539f, 0.237868f, -0.121796f, 0.0715619f, 0.106992f, + -0.621862f, -0.167142f, 0.153716f, 0.0570912f, -0.06525f, + -0.923773f, 0.130759f, 0.0517066f, 0.0729862f, -0.873064f, + 0.0403328f, -0.186499f, -0.0831918f, -0.223723f, 0.144697f, + 0.212845f, 0.416876f, 0.361598f, 0.138229f, 0.0728777f, + -1.95419f, -0.00382816f, -0.0440387f, 0.433627f, 0.44781f, + -1.05229f, -1.54506f, 0.564827f, -0.263456f, 0.296105f, + -0.158055f, 0.388274f, -0.366639f, 0.212006f, -0.245619f, + 0.593064f, 0.088727f, 0.410632f, -0.263462f, 0.507075f, + -0.0974155f, 0.275268f, -0.1293f, 0.136679f, 1.98276f, + 0.411766f, 0.391987f, 0.34283f, -0.114077f, 0.258462f, + -0.302443f, 0.301138f, -0.00726621f, 0.276441f, -0.291582f, + 0.66498f, -0.321451f, -0.332805f, 0.0943272f, 0.572253f, + -0.45818f, -0.0219593f, -0.151679f, 0.402033f, -1.15502f, + -0.882955f, 0.772904f, 0.88126f, -0.149555f, 0.709525f, + 0.350116f, -0.21531f, 0.797893f, 0.0230234f, 0.0203034f, + 0.2744f, 1.08273f, 0.039349f, 0.503909f, -0.45892f, + -0.579516f, -0.344058f, 0.390628f, -0.386941f, -0.430317f, + -0.0807066f, 0.435906f, 0.522996f, 0.724476f, -0.74371f, + -0.05376f, -0.340898f, -0.962646f, -0.0278005f, 0.0981149f, + -0.0811161f, 0.00237994f, 0.850042f, 0.0665473f, 0.134413f }; -static const float simple_motion_search_prune_part_layer_0_bias_8[] = { - -1.75332f, 0.419404f, -0.0423004f, 0.345601f, -2.40097f, -0.574857f, - -2.53366f, -0.207096f, -1.08866f, 0.801763f, -2.72428f, -2.39884f, - 1.04072f, -0.782749f, -1.47003f, -2.98207f, 0.8829f, 1.81741f, - -2.02369f, 0.241717f, -0.178749f, -3.00588f, -0.232007f, 0.21717f +static const float av1_simple_motion_search_prune_part_logits_bias_8[] = { + 1.63404f, -0.715866f, -1.0132f, -2.08745f }; -static const NN_CONFIG simple_motion_search_prune_part_nn_config_8 = { +static const NN_CONFIG av1_simple_motion_search_prune_part_nn_config_8 = { NUM_FEATURES_8, NUM_LOGITS_8, NUM_HIDDEN_LAYERS_8, @@ -3770,12 +3967,12 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_8 = { NUM_LAYER_0_UNITS_8, }, { - simple_motion_search_prune_part_layer_0_kernel_8, - simple_motion_search_prune_part_logits_kernel_8, + av1_simple_motion_search_prune_part_layer_0_kernel_8, + av1_simple_motion_search_prune_part_logits_kernel_8, }, { - simple_motion_search_prune_part_layer_0_bias_8, - simple_motion_search_prune_part_logits_bias_8, + av1_simple_motion_search_prune_part_layer_0_bias_8, + av1_simple_motion_search_prune_part_logits_bias_8, }, }; @@ -3785,75 +3982,824 @@ static const NN_CONFIG simple_motion_search_prune_part_nn_config_8 = { #undef NUM_LOGITS_8 #define FEATURE_SIZE 19 -static const float two_pass_split_partition_weights_128[FEATURE_SIZE + 1] = { +static const float av1_2pass_split_partition_weights_128[FEATURE_SIZE + 1] = { 2.683936f, -0.193620f, -4.106470f, -0.141320f, -0.282289f, 0.125296f, -1.134961f, 0.862757f, -0.418799f, -0.637666f, 0.016232f, 0.345013f, 0.018823f, -0.393394f, -1.130700f, 0.695357f, 0.112569f, -0.341975f, -0.513882f, 5.7488966f, }; -static const float two_pass_split_partition_weights_64[FEATURE_SIZE + 1] = { +static const float av1_2pass_split_partition_weights_64[FEATURE_SIZE + 1] = { 2.990993f, 0.423273f, -0.926544f, 0.454646f, -0.292698f, -1.311632f, -0.284432f, 0.717141f, -0.419257f, -0.574760f, -0.674444f, 0.669047f, -0.374255f, 0.380624f, -0.804036f, 0.264021f, 0.004163f, 1.896802f, 0.924287f, 0.13490619f, }; -static const float two_pass_split_partition_weights_32[FEATURE_SIZE + 1] = { +static const float av1_2pass_split_partition_weights_32[FEATURE_SIZE + 1] = { 2.795181f, -0.136943f, -0.924842f, 0.405330f, -0.463505f, -0.584076f, -0.831472f, 0.382985f, -0.597544f, -0.138915f, -1.354350f, 0.466035f, -0.553961f, 0.213202f, -1.166429f, 0.010776f, -0.096236f, 2.335084f, 1.699857f, -0.58178353f, }; -static const float two_pass_split_partition_weights_16[FEATURE_SIZE + 1] = { +static const float av1_2pass_split_partition_weights_16[FEATURE_SIZE + 1] = { 1.987888f, -0.431100f, -1.687703f, 0.262602f, -0.425298f, -0.463870f, -1.493457f, 0.470917f, -0.528457f, -0.087700f, -1.815092f, 0.152883f, -0.337908f, 0.093679f, -1.548267f, -0.042387f, -0.000861f, 2.556746f, 1.619192f, 0.03643292f, }; -static const float two_pass_split_partition_weights_8[FEATURE_SIZE + 1] = { +static const float av1_2pass_split_partition_weights_8[FEATURE_SIZE + 1] = { 2.188344f, -0.817528f, -2.119219f, 0.000000f, -0.348167f, -0.658074f, -1.960362f, 0.000000f, -0.403080f, 0.282699f, -2.061088f, 0.000000f, -0.431919f, -0.127960f, -1.099550f, 0.000000f, 0.121622f, 2.017455f, 2.058228f, -0.15475988f, }; -static const float two_pass_none_partition_weights_128[FEATURE_SIZE + 1] = { +static const float av1_2pass_none_partition_weights_128[FEATURE_SIZE + 1] = { -1.006689f, 0.777908f, 4.461072f, -0.395782f, -0.014610f, -0.853863f, 0.729997f, -0.420477f, 0.282429f, -1.194595f, 3.181220f, -0.511416f, 0.117084f, -1.149348f, 1.507990f, -0.477212f, 0.202963f, -1.469581f, 0.624461f, -0.89081228f, }; -static const float two_pass_none_partition_weights_64[FEATURE_SIZE + 1] = { +static const float av1_2pass_none_partition_weights_64[FEATURE_SIZE + 1] = { -1.241117f, 0.844878f, 5.638803f, -0.489780f, -0.108796f, -4.576821f, 1.540624f, -0.477519f, 0.227791f, -1.443968f, 1.586911f, -0.505125f, 0.140764f, -0.464194f, 1.466658f, -0.641166f, 0.195412f, 1.427905f, 2.080007f, -1.98272777f, }; -static const float two_pass_none_partition_weights_32[FEATURE_SIZE + 1] = { +static const float av1_2pass_none_partition_weights_32[FEATURE_SIZE + 1] = { -2.130825f, 0.476023f, 5.907343f, -0.516002f, -0.097471f, -2.662754f, 0.614858f, -0.576728f, 0.085261f, -0.031901f, 0.727842f, -0.600034f, 0.079326f, 0.324328f, 0.504502f, -0.547105f, -0.037670f, 0.304995f, 0.369018f, -2.66299987f, }; -static const float two_pass_none_partition_weights_16[FEATURE_SIZE + 1] = { +static const float av1_2pass_none_partition_weights_16[FEATURE_SIZE + 1] = { -1.626410f, 0.872047f, 5.414965f, -0.554781f, -0.084514f, -3.020550f, 0.467632f, -0.382280f, 0.199568f, 0.426220f, 0.829426f, -0.467100f, 0.153098f, 0.662994f, 0.327545f, -0.560106f, -0.141610f, 0.403372f, 0.523991f, -3.02891231f, }; -static const float two_pass_none_partition_weights_8[FEATURE_SIZE + 1] = { +static const float av1_2pass_none_partition_weights_8[FEATURE_SIZE + 1] = { -1.463349f, 0.375376f, 4.751430f, 0.000000f, -0.184451f, -1.655447f, 0.443214f, 0.000000f, 0.127961f, 0.152435f, 0.083288f, 0.000000f, 0.143105f, 0.438012f, 0.073238f, 0.000000f, -0.278137f, 0.186134f, 0.073737f, -1.6494962f, }; +#undef FEATURE_SIZE + +// nn model for predicting max square partition level of a superblock +#define NUM_HIDDEN_LAYERS 1 +#define NUM_FEATURES 13 +#define NUM_LAYER_0_UNITS 48 +#define NUM_LOGITS 4 + +static const float av1_max_part_pred_logits_kernel[] = { + -0.304561f, 0.0885596f, -0.988539f, 1.08147f, 0.215213f, + 0.202965f, -0.828457f, -0.233945f, -0.0866977f, -0.115521f, + 0.02079f, 0.196491f, -0.0285075f, 0.05067f, -0.00872862f, + 0.00281844f, -0.238954f, 0.0253801f, 0.0257775f, 0.339269f, + 0.176174f, -0.152545f, -0.0588704f, -1.62275f, -0.189329f, + 0.0808033f, 0.233844f, -4.53798f, 0.674968f, -0.0361688f, + -0.0754075f, 1.16129f, -0.0188879f, 0.113255f, -3.04378f, + 0.814728f, -0.568517f, -0.00179383f, -3.61223f, -1.67535f, + -2.20417f, -0.197196f, 0.0507745f, -0.0909394f, -0.0507879f, + -1.27999f, -0.055623f, 0.0318497f, 0.192867f, 0.138726f, + 0.0443392f, -0.595075f, -0.166774f, 0.0882958f, -0.348161f, + 0.0214428f, -0.0599275f, -0.0995385f, -0.82358f, 0.141205f, + -0.053232f, 0.00508296f, -1.90872f, 1.15004f, -0.194219f, + 0.0229019f, -0.00354318f, 0.22016f, 0.154101f, -0.159231f, + -0.0446647f, -0.197503f, 0.0408453f, 0.197659f, 0.797858f, + -0.189722f, 0.343653f, 0.124666f, -1.03083f, 0.603059f, + 0.101565f, 0.0932993f, 0.462484f, 0.295984f, 1.11198f, + 0.143709f, -0.846232f, -0.464392f, -1.06058f, -0.124889f, + 0.0727475f, 1.18446f, -0.100302f, 0.0641918f, -0.101622f, + 0.10219f, 0.130189f, 0.0915623f, -0.166904f, -1.10606f, + -0.16726f, -0.146152f, 0.145443f, -0.177091f, -0.0215214f, + 0.0158506f, -0.553294f, 0.0784749f, -0.0416628f, -0.027785f, + 0.280027f, 0.484898f, -0.164225f, 0.0238317f, -0.0345254f, + 0.0410244f, 0.131529f, 0.0239622f, -0.0749436f, -0.0224914f, + 0.128926f, 0.224539f, 0.413297f, 0.0638572f, 0.103308f, + 0.0913242f, -0.119274f, 0.0163103f, 0.113828f, 0.119809f, + 0.297057f, -0.124889f, -0.533108f, -0.181408f, -0.129896f, + 0.0221064f, -0.0773281f, -0.0386467f, 0.0342961f, 0.126575f, + -0.24114f, 0.0735576f, 0.0524791f, 0.246896f, -0.130674f, + -0.03979f, 0.173639f, 1.95193f, -0.113029f, -0.0305852f, + -0.00671737f, 0.157159f, -0.00102858f, -0.543688f, 0.566772f, + 0.124124f, -0.0294064f, -0.0699021f, -0.0704103f, -0.766097f, + -0.0625802f, -0.0906173f, -0.0520414f, -0.0272724f, 0.283064f, + 0.236213f, -0.127319f, 0.019392f, 0.170042f, -0.0214542f, + 0.0740938f, 0.356578f, -0.236257f, 0.269021f, 0.114759f, + -0.641166f, 0.136308f, -0.0386959f, -0.112024f, -0.361209f, + 0.686095f, 0.183906f, 0.288656f, 0.182007f, 0.337458f, + 0.058974f, -0.305512f, -0.841708f, -0.243779f, -0.0614058f, + 0.208747f, 0.448697f +}; + +static const float av1_max_part_pred_layer_0_bias[] = { + -0.776544f, -2.0022f, -0.330294f, 2.47665f, 1.90206f, -1.61571f, + 0.536246f, 1.00455f, 5.24561f, 1.55111f, -0.816399f, -4.88703f, + -1.06417f, -1.15359f, -0.145289f, 1.91831f, 0.630915f, -1.94256f, + -3.35239f, -1.05007f, -1.05186f, 1.36824f, -5.2878f, 1.10482f, + -5.00077f, -0.0445198f, 3.41427f, 2.3439f, -0.413306f, -1.88152f, + -2.28638f, 8.24783f, -1.91961f, -1.49324f, 1.96599f, -6.32309f, + -0.332426f, -0.425506f, 4.06511f, 5.84386f, 4.15747f, 1.22402f, + 2.8512f, 2.53027f, 0.0170272f, -1.43966f, -0.997785f, 5.43064f +}; + +static const float av1_max_part_pred_logits_bias[] = { -4.25432f, 0.144758f, + 1.96217f, 0.728905f }; + +static const float av1_max_part_pred_layer_0_kernel[] = { + 0.992471f, 0.533006f, 0.143743f, -2.51788f, -0.468337f, + -0.201376f, -0.151834f, 0.479883f, 1.16061f, -0.278878f, + -0.814954f, -0.152405f, -0.0521608f, 0.797104f, -2.08912f, + 0.385839f, -2.22889f, -0.106858f, -0.239766f, -0.951128f, + -0.698753f, 0.0831051f, 1.1702f, 0.342834f, -0.0352795f, + -0.0847639f, -0.802086f, 0.258982f, 1.14174f, 0.645885f, + -1.19226f, -0.592888f, -0.343659f, 1.1912f, 1.45411f, + -1.22927f, 0.152858f, 0.00373585f, -1.60637f, 0.592611f, + 0.0857475f, -0.346147f, -0.150784f, -0.0817408f, -0.189918f, + -0.804952f, -1.33036f, -1.03307f, 0.0248769f, 0.16607f, + -2.896f, -2.1293f, 0.12293f, -0.173179f, -0.212128f, + -6.76221f, 0.033188f, 0.0231787f, 0.905957f, 0.0551327f, + -0.356276f, 0.0181795f, 0.0977523f, -0.0352873f, -0.0396386f, + 2.3241f, 0.0632874f, -0.11804f, -6.32521f, 0.0224659f, + -0.00188896f, 0.267992f, 0.272337f, 0.00936963f, 0.659969f, + -2.25707f, -0.0278229f, -0.0185089f, -1.14466f, 0.104827f, + 0.0435885f, 0.558586f, -0.00697004f, 0.0312611f, 0.540574f, + -0.568625f, 0.218608f, 0.378911f, -0.0289192f, -0.0734742f, + -1.08782f, -2.42069f, -0.0127239f, 0.0493651f, -1.15837f, + 0.261831f, 0.401824f, -1.04545f, 0.284173f, 0.784972f, + -0.511243f, -0.982599f, -0.106134f, -0.325964f, -1.44107f, + -1.42434f, -1.02402f, -1.52034f, 0.0737116f, 0.0462242f, + 0.628722f, -1.0405f, -0.113718f, 2.20573f, -4.33951f, + -0.0192695f, -0.0229314f, -1.89156f, 0.645942f, 0.375708f, + -1.97447f, -0.267014f, 0.0989443f, -0.450534f, -1.01737f, + -0.642416f, -0.0897288f, -2.08724f, -0.190965f, -0.279135f, + -0.830178f, 0.808754f, -0.139091f, 1.11004f, -0.454439f, + -0.479238f, -1.44001f, 0.0888059f, 0.885689f, -0.642505f, + -0.00773651f, -0.0265721f, -0.906346f, 1.68504f, 0.084257f, + -0.951101f, -8.06495f, 0.19231f, 0.16389f, -0.193678f, + 0.729837f, -1.98392f, -5.98513f, 3.32638f, -0.0658378f, + -0.0910426f, -0.666567f, -0.315339f, 0.123124f, -2.66375f, + -0.714852f, -0.136176f, -0.460166f, -0.567551f, -1.06193f, + -1.21389f, -0.83865f, 0.00280695f, -0.199519f, -0.534704f, + 0.419311f, -0.149008f, -3.68707f, 0.00285113f, -0.0718198f, + -1.41026f, -1.34155f, -0.538687f, -0.623666f, -2.56462f, + -0.0183333f, -0.323532f, -1.27141f, -0.0212039f, 0.198633f, + 0.459554f, -4.65103f, -1.01293f, -1.39512f, -0.289026f, + 0.208724f, -0.665226f, 1.13369f, -1.96734f, -1.45442f, + -3.46172f, 0.810681f, -0.603973f, 0.842764f, -3.90371f, + -0.394561f, -3.61363f, -2.88085f, 0.031645f, -0.23125f, + -2.63898f, -1.35314f, -0.46726f, 1.33145f, 1.20269f, + 1.38682f, -0.331637f, 0.069021f, 0.149523f, -1.24957f, + -0.878857f, -0.200368f, 0.465744f, 1.01365f, -0.0122221f, + -0.550586f, -1.12581f, -0.422132f, -0.0744868f, -2.4804f, + -1.07072f, -0.479006f, 0.101817f, -0.118947f, 0.341576f, + -1.0538f, -0.812346f, -1.13727f, -0.00939806f, 10.1571f, + -0.0441302f, 0.00280407f, -21.5044f, 0.0181152f, -0.0143246f, + 3.23462f, -1.38624f, -1.80416f, 4.89763f, -2.67364f, + 2.31771e-05f, 0.000393989f, 0.352204f, -0.193455f, 0.531455f, + 0.488757f, -0.442555f, -0.518528f, 0.431482f, -2.67727f, + -2.00626f, -0.39729f, -0.221494f, -0.0188888f, -0.0377649f, + -1.80169f, 0.0810332f, -0.0408335f, -1.28675f, -0.0353824f, + -0.666723f, -1.07281f, 0.252912f, -1.24547f, -1.7831f, + -1.14354f, -0.137662f, 0.00230182f, 0.736862f, 0.175872f, + -0.187556f, 0.43963f, -0.796524f, 0.056219f, -0.387874f, + 0.0710224f, -0.16548f, -0.100993f, 0.931481f, -3.20738f, + -0.0197576f, 0.266148f, -0.173909f, -0.337795f, -0.0682381f, + 0.176844f, 0.140286f, 1.12033f, 0.429064f, -2.24192f, + -1.54682f, 2.23646f, -0.0371138f, -0.0475339f, -3.21766f, + 0.0412858f, 0.387811f, 6.6711f, 0.140649f, 0.0559547f, + -0.802839f, 0.599977f, 0.64552f, -2.08103f, -0.503401f, + -0.0407036f, -0.0299199f, 0.0849445f, -0.111657f, -1.63462f, + 3.33762f, 0.0441394f, 0.0466889f, -0.951806f, 0.0723954f, + 0.00348661f, -1.36903f, 2.24625f, -0.0348915f, -0.0508893f, + -0.240891f, -0.120143f, -0.17991f, -2.09137f, 0.0150871f, + 0.0480333f, 1.72012f, 0.0309551f, -0.0370507f, -0.377075f, + 0.103916f, -0.0169255f, -0.0145395f, -4.02144f, 0.83193f, + -0.316502f, 6.3832f, -1.70038f, -1.97215f, -1.94501f, + 1.45479f, 0.711725f, -0.348496f, -0.279056f, -1.13396f, + -1.51744f, -0.853307f, 1.53131f, -0.0032358f, 1.41808f, + -1.32989f, -0.245221f, -0.161614f, -0.500845f, -0.449252f, + 0.0724151f, -0.116333f, -0.0946182f, -2.0945f, 0.0564572f, + 0.393261f, -1.06861f, -0.111458f, -0.839943f, -0.0880348f, + 0.0365742f, 0.415339f, -1.57494f, -0.713697f, 1.02349f, + -0.221371f, -0.0446281f, 1.89223f, -0.0811754f, -0.402773f, + -0.930987f, 0.0243194f, 0.0678332f, -0.0233014f, 0.165372f, + -0.44083f, -1.2404f, 0.35675f, -0.040916f, -0.0512548f, + -2.9071f, 0.861174f, -0.778133f, 2.14436f, -0.688427f, + -0.480371f, -1.69032f, 0.706687f, -0.281982f, -2.30451f, + 1.61541f, -0.0213638f, -0.740509f, -0.266677f, 0.0268434f, + -0.0116908f, -3.17595f, 0.0114825f, 0.0196997f, -0.144005f, + 0.0550181f, -0.851459f, -0.000285073f, -0.538441f, -0.0254868f, + -0.0104454f, -0.0661998f, -0.196469f, -0.346372f, -5.52892f, + -0.643683f, -0.622224f, -0.31463f, -0.555956f, -0.520132f, + -0.843166f, -2.59479f, -0.750195f, 0.00635995f, -0.338615f, + -0.216676f, -0.391544f, -1.62185f, -0.718471f, -0.475406f, + -0.782041f, -0.608824f, -1.09633f, -1.27308f, -0.560719f, + -0.207539f, -0.0196445f, -1.05519f, -0.575249f, -1.0642f, + 1.01615f, -0.873633f, -0.417953f, -0.428051f, 0.350259f, + -2.53833f, -2.72203f, 0.672846f, -0.503094f, -1.1374f, + 0.214291f, 0.013305f, 0.0112064f, 1.10532f, 0.030455f, + 0.0239614f, 0.628072f, 0.0539135f, -0.472441f, -0.688439f, + -0.32044f, -0.0234867f, -0.0158436f, -0.949314f, -0.0453161f, + -1.18306f, 0.626845f, -0.426925f, -0.688371f, 0.415062f, + 0.0640985f, -0.638387f, -2.01399f, -0.209744f, -0.762892f, + -0.0753296f, -0.879315f, -0.520433f, -0.111375f, 0.389742f, + -0.398862f, -0.643227f, -0.246396f, 0.0317051f, 1.06973f, + 0.413617f, 0.180506f, -0.0507897f, -0.00650435f, 0.620892f, + 0.046312f, 0.475032f, 0.906993f, -0.0388061f, -0.256271f, + -1.03323f, 0.0125266f, -0.31116f, -0.377611f, -0.0386407f, + -0.0232745f, -0.353644f, -2.27289f, 0.0571779f, -0.00865006f, + 1.65101f, 0.0175711f, 0.0184585f, 0.558458f, 0.2213f, + -0.285089f, 0.433445f, -0.427177f, -0.0103682f, -0.0101273f, + 0.214085f, -0.0459885f, 0.00761981f, 0.836381f, 0.0175293f, + 0.02508f, -1.51778f, 0.0143956f, -0.162589f, 0.595418f, + 0.21445f, -0.0335848f, -0.0136684f, -0.16686f, -0.14612f, + 0.0816238f, 0.499636f, 0.12458f, -2.41673f, -0.261721f, + -0.676805f, -1.88366f, 0.730462f, 0.69196f, -0.0288489f, + -2.38272f, 0.329876f, 0.014517f, -0.115145f, -3.48151f, + -0.00209072f, -0.0732377f, 0.820443f, -0.0118701f, 0.112145f, + 0.272315f, 0.137531f, -0.0200997f, -0.0397883f, -2.19458f, + 0.183554f, -0.639716f, 0.481605f, -0.621639f, -0.0980299f, + -0.710534f, -0.143105f, -6.77626f, -1.65139f, -2.37718f, + -0.533127f, -1.12574f, 3.34182f, -0.0758663f, 0.0334238f, + -9.48647f, 0.0674974f, 0.0507665f, 0.523007f, -0.0668f, + 0.5736f, -0.589761f, -1.1692f, -0.0236497f, -0.00828928f, + -0.265823f, 1.15284f, 0.307927f, -0.695308f, 0.13725f, + -0.20394f, -0.363965f, -0.331159f, -1.50927f, -1.20051f, + -0.0205825f, -0.0381859f, -0.0579876f, -1.6913f, -1.94626f, + 3.4214f, 3.3922f, -2.13798f, -0.679848f, -0.890735f, + 0.235017f, -0.253202f, -1.0571f, 1.40354f, 0.00719052f, + -1.54365f, -0.7289f, -1.05492f, 0.0238169f, -0.00543592f, + -0.0510353f, -0.175386f, -0.724207f, -0.788936f, 0.039976f, + 1.36966f, 0.869475f, -0.0302774f, -0.0537556f +}; + +static const NN_CONFIG av1_max_part_pred_nn_config = { + NUM_FEATURES, + NUM_LOGITS, + NUM_HIDDEN_LAYERS, + { + NUM_LAYER_0_UNITS, + }, + { + av1_max_part_pred_layer_0_kernel, + av1_max_part_pred_logits_kernel, + }, + { + av1_max_part_pred_layer_0_bias, + av1_max_part_pred_logits_bias, + }, +}; + +#undef NUM_HIDDEN_LAYERS +#undef NUM_FEATURES +#undef NUM_LAYER_0_UNITS +#undef NUM_LOGITS + +// Early termination in second pass +static const float av1_simple_motion_search_term_none_mean_128[28] = { + 12.661922f, 12.638062f, 10.896497f, 10.865719f, 10.978963f, 10.940105f, + 11.012235f, 10.972760f, 11.069924f, 11.018533f, 11.773865f, 11.747426f, + 11.891315f, 11.858107f, 11.793916f, 11.766356f, 11.874997f, 11.840164f, + 5.940535f, 0.770746f, 4.292692f, 4.309581f, 0.848423f, 4.292334f, + 4.298179f, 8.514713f, 14.911736f, 19.825352f, +}; + +static const float av1_simple_motion_search_term_none_std_128[28] = { + 1.796731f, 1.797056f, 1.898383f, 1.900753f, 1.846624f, 1.846953f, 1.906632f, + 1.908089f, 1.836533f, 1.835967f, 1.840262f, 1.840671f, 1.816836f, 1.817103f, + 1.879846f, 1.881333f, 1.803102f, 1.802654f, 2.263402f, 0.420354f, 1.117165f, + 1.083779f, 0.358611f, 1.101183f, 1.084938f, 2.462638f, 1.577009f, 1.574711f, +}; + +static const float av1_simple_motion_search_term_none_mean_64[28] = { + 10.904455f, 10.853546f, 9.247903f, 9.184479f, 9.251985f, 9.186686f, + 9.253490f, 9.190190f, 9.270079f, 9.204357f, 10.086511f, 10.031060f, + 10.100875f, 10.045429f, 10.069688f, 10.013173f, 10.082980f, 10.024640f, + 4.888378f, 0.878113f, 3.598450f, 3.628491f, 0.925833f, 3.560971f, + 3.573322f, 8.807137f, 13.348477f, 18.269117f, +}; + +static const float av1_simple_motion_search_term_none_std_64[28] = { + 1.789300f, 1.787061f, 1.823519f, 1.820226f, 1.794643f, 1.788620f, 1.797194f, + 1.795135f, 1.777795f, 1.773634f, 1.794000f, 1.790377f, 1.772197f, 1.769692f, + 1.819050f, 1.817139f, 1.793577f, 1.789333f, 1.998251f, 0.327156f, 0.885748f, + 0.853767f, 0.262043f, 0.902435f, 0.860033f, 1.224865f, 1.603411f, 1.589296f, +}; + +static const float av1_simple_motion_search_term_none_mean_32[28] = { + 9.818970f, 9.751199f, 8.015079f, 7.927318f, 8.029113f, 7.938330f, 8.012570f, + 7.923719f, 8.033508f, 7.941911f, 8.933057f, 8.857422f, 8.935639f, 8.859187f, + 8.905495f, 8.829741f, 8.929428f, 8.851351f, 4.114069f, 0.954752f, 2.645082f, + 2.709703f, 0.964678f, 2.652077f, 2.673393f, 9.430499f, 11.922798f, 16.942251f, +}; + +static const float av1_simple_motion_search_term_none_std_32[28] = { + 1.737107f, 1.734327f, 1.727923f, 1.720244f, 1.721570f, 1.712775f, 1.718028f, + 1.710370f, 1.711612f, 1.702596f, 1.754856f, 1.748855f, 1.741871f, 1.736304f, + 1.722428f, 1.717380f, 1.713563f, 1.707582f, 1.761170f, 0.207847f, 0.900058f, + 0.862356f, 0.184593f, 0.903822f, 0.856120f, 1.529199f, 1.412085f, 1.453153f, +}; + +static const float av1_simple_motion_search_term_none_mean_16[28] = { + 8.998877f, 8.912468f, 7.085255f, 6.953476f, 7.086386f, 6.954091f, 7.088727f, + 6.955747f, 7.093955f, 6.960635f, 8.065050f, 7.961432f, 8.071631f, 7.967233f, + 8.041699f, 7.937715f, 8.046791f, 7.942183f, 3.833521f, 0.978421f, 1.901347f, + 1.950124f, 0.979418f, 1.928000f, 1.936727f, 9.773951f, 10.735227f, 15.949769f, +}; + +static const float av1_simple_motion_search_term_none_std_16[28] = { + 1.641193f, 1.640172f, 1.614794f, 1.608906f, 1.609571f, 1.603580f, 1.606928f, + 1.601246f, 1.599230f, 1.593529f, 1.633747f, 1.630219f, 1.625695f, 1.622547f, + 1.633827f, 1.630182f, 1.626607f, 1.622777f, 1.548838f, 0.145303f, 0.744550f, + 0.736552f, 0.141980f, 0.742979f, 0.736977f, 1.366255f, 1.258794f, 1.294309f, +}; + +static const float av1_simple_motion_search_term_none_model_128[] = { + -0.6106842357f, -1.0402954455f, 0.6054417656f, -0.2116623578f, + 0.2447714930f, 0.3782256209f, 0.5095592479f, -0.3275620904f, + 0.3886188013f, 0.2629499420f, -0.1979599415f, -0.5389565605f, + 0.1209207902f, -0.4913347466f, 0.3798542731f, -0.2812861709f, + -0.1049824167f, -0.1088672020f, 0.4059596517f, -0.1347896613f, + 0.2276868621f, 0.0506386970f, 0.0071088411f, 0.0467952100f, + 0.2091247458f, -0.7371964736f, 0.1368935545f, 0.3175247786f, + -0.5493146094f, +}; + +static const float av1_simple_motion_search_term_none_model_64[] = { + -0.4150046575f, -0.3954358561f, 0.1997997444f, 0.3395826831f, + 0.2827215753f, 0.3395683652f, 0.2483140395f, 0.2722216476f, + 0.2610308009f, 0.3724974359f, -0.0551479654f, -0.1721616359f, + -0.3459358629f, -0.0952524186f, -0.1428993840f, -0.0415654914f, + -0.3169539902f, -0.0269429900f, 0.9891530919f, -0.0125084982f, + 0.0972182377f, 0.0008889801f, 0.0205418050f, 0.0057237854f, + 0.1005222691f, -0.2851321920f, -1.5150336445f, 0.1893942436f, + -0.4337360901f, +}; + +static const float av1_simple_motion_search_term_none_model_32[] = { + -0.4667392852f, -0.3893302767f, 0.1603498635f, 0.2304974726f, + 0.1404975592f, 0.2505516225f, 0.1423053884f, 0.2189318406f, + 0.1379765409f, 0.2638241296f, -0.1342865463f, -0.0549054345f, + -0.1925223436f, -0.1142702769f, 0.0127811659f, 0.0868639997f, + -0.0643197251f, 0.0279496470f, 0.9904395769f, -0.0095178685f, + 0.1179410649f, -0.0013411972f, 0.0095060660f, 0.0195730400f, + 0.0779717771f, -0.2498860763f, -0.8168817125f, -0.4798397348f, + -0.6609679881f, +}; + +static const float av1_simple_motion_search_term_none_model_16[] = { + -0.3021081992f, -0.4620153673f, 0.0448577479f, 0.1738455035f, + 0.0663209177f, 0.1629614573f, 0.0555168744f, 0.1631870212f, + 0.0425805150f, 0.1688564954f, 0.0434083772f, -0.0046603915f, + -0.0271580056f, -0.0183879127f, 0.1073730471f, 0.0314201476f, + 0.0576891756f, 0.0119723753f, 0.9084332022f, -0.0188429077f, + 0.0755089811f, -0.0172550234f, 0.0037663075f, 0.0022094472f, + 0.0500247894f, -0.2944572004f, -0.8908521199f, -0.2555515792f, + -0.5396254205f, +}; + +// Early termination in firstpass +static const float av1_fp_simple_motion_search_term_none_mean_32[20] = { + 10.216787f, 10.167575f, 8.405353f, 8.340786f, 8.436503f, + 8.373259f, 8.444113f, 8.379074f, 8.448215f, 8.384669f, + 4.107491f, 0.923902f, 2.702687f, 2.712742f, 0.953166f, + 2.703244f, 2.707070f, 9.549801f, 12.013671f, 17.059454f, +}; + +static const float av1_fp_simple_motion_search_term_none_std_32[20] = { + 1.886182f, 1.886638f, 1.884324f, 1.883410f, 1.851800f, 1.851652f, 1.847129f, + 1.848014f, 1.832187f, 1.832360f, 1.758185f, 0.265155f, 0.939592f, 0.932395f, + 0.211284f, 0.950024f, 0.945295f, 1.846744f, 1.453674f, 1.505994f, +}; + +static const float av1_fp_simple_motion_search_term_none_mean_16[20] = { + 9.131485f, 9.065489f, 7.254479f, 7.158092f, 7.274240f, 7.178158f, 7.278780f, + 7.182110f, 7.278793f, 7.182714f, 3.981902f, 0.964040f, 2.080875f, 2.087185f, + 0.973397f, 2.088189f, 2.090166f, 9.386505f, 10.826546f, 15.985614f, +}; + +static const float av1_fp_simple_motion_search_term_none_std_16[20] = { + 1.681172f, 1.688587f, 1.710854f, 1.717533f, 1.684010f, 1.691476f, 1.683537f, + 1.691523f, 1.674699f, 1.682130f, 1.639731f, 0.186191f, 0.796448f, 0.795075f, + 0.160921f, 0.791005f, 0.790048f, 1.430960f, 1.337976f, 1.370498f, +}; + +static const float av1_fp_simple_motion_search_term_none_mean_8[20] = { + 7.821461f, 7.714526f, 5.799360f, 5.606948f, 5.805885f, 5.614357f, 5.794252f, + 5.599669f, 5.798780f, 5.605399f, 4.069016f, 0.977720f, 1.577513f, 1.581266f, + 0.983371f, 1.524603f, 1.524952f, 9.221803f, 9.508886f, 14.972815f, +}; + +static const float av1_fp_simple_motion_search_term_none_std_8[20] = { + 1.618036f, 1.634415f, 1.652861f, 1.672006f, 1.646337f, 1.664935f, 1.650876f, + 1.670476f, 1.645141f, 1.664301f, 1.502258f, 0.147592f, 0.760353f, 0.762547f, + 0.127879f, 0.741096f, 0.742186f, 1.042003f, 1.292524f, 1.250398f, +}; + +#define NUM_HIDDEN_LAYERS_32 1 +#define NUM_FEATURES_32 20 +#define NUM_LAYER_0_UNITS_32 20 +#define NUM_LOGITS_32 1 + +static const float + av1_fp_simple_motion_search_term_none_hiddenlayer_0_kernel_32[] = { + -0.293987f, 0.796773f, -0.0888487f, -0.00796495f, -0.343768f, + 0.0783252f, 0.0596814f, -0.235432f, -0.0780005f, -0.409017f, + -0.256821f, -0.281654f, 1.00889f, 0.701893f, -0.0181661f, + 0.119718f, 0.0956582f, 0.76792f, 0.235693f, 0.351628f, + -1.28111f, -1.45847f, 0.387732f, 0.476054f, 0.384561f, + 0.427465f, 0.11875f, -0.0176598f, -0.0528453f, 0.395589f, + -0.331994f, 0.0442108f, 0.195171f, -0.0377402f, -0.0736457f, + -0.0490903f, 0.116165f, -0.549512f, 0.12968f, 0.641055f, + -1.03066f, -0.601979f, 0.351981f, -0.122019f, 0.00869275f, + 0.399222f, -0.343995f, -0.444257f, -0.160805f, -0.537537f, + 0.261478f, -0.163785f, 0.218916f, 0.106506f, -0.103819f, + 0.0121841f, 0.284757f, -0.362989f, 1.10793f, 0.477236f, + -0.424117f, -0.884156f, -0.468291f, -0.510531f, 0.791441f, + 0.75243f, 0.839871f, 0.604127f, -0.182956f, -0.246703f, + -1.25861f, 0.0546303f, 0.0811323f, 0.00655988f, 0.0286305f, + -0.00938366f, -0.0291418f, -0.231632f, -0.331077f, 1.12479f, + -0.635514f, -0.146066f, 0.853122f, 0.923699f, 0.180011f, + -0.252973f, 0.1474f, -0.454344f, 0.354736f, 0.576872f, + -1.43275f, 0.0327868f, 0.140849f, -0.102523f, 0.0524867f, + 0.007091f, -0.00232578f, -0.536116f, -0.700144f, 0.166646f, + 0.0636548f, 0.44645f, -0.346062f, -0.685779f, -1.0792f, + -0.999219f, 0.442744f, 0.371198f, 0.777914f, 0.719409f, + -0.417984f, 0.0602868f, 0.0225539f, 0.0457407f, 0.0249501f, + 0.0126021f, 0.00450792f, 0.0485095f, 0.203485f, 0.584116f, + -0.599426f, -0.244633f, 0.168231f, -0.00134934f, -0.106987f, + -0.0490239f, -0.22029f, 0.138017f, 0.373674f, 0.00638684f, + -2.08003f, 0.106453f, 0.124456f, -0.0286108f, 0.0422698f, + 0.013734f, 0.0780971f, -0.40173f, 0.473453f, 1.16836f, + -0.251035f, 0.0119074f, 0.319241f, 0.0422023f, -0.730454f, + -0.745948f, 0.796709f, 0.277634f, 0.09711f, -0.212224f, + 0.825348f, 0.0208521f, -0.0238098f, 0.00929265f, 0.0516351f, + -0.02329f, 0.0983163f, -0.180721f, 0.0122096f, -0.246159f, + 0.61468f, 0.923765f, 0.240435f, -0.294845f, -0.495317f, + -0.0563837f, -0.417936f, 0.154874f, -0.604407f, -0.0681337f, + -0.65738f, -0.0270073f, 0.0920023f, -0.0742724f, 0.820862f, + -0.602758f, -1.20617f, -0.201707f, 0.869499f, -0.0539076f, + 0.403097f, 0.429168f, -0.938227f, -0.830894f, -0.362462f, + -0.0658648f, 0.471469f, -0.264827f, 0.610275f, 0.367995f, + 0.735662f, -0.0473157f, -0.0380545f, -0.0848067f, -0.146108f, + -0.125875f, -0.0576117f, -0.296198f, -0.100443f, -0.212971f, + 0.593524f, 1.23111f, -0.810009f, -0.604572f, 0.203021f, + 0.256285f, -1.17049f, -1.19156f, 0.24365f, 0.727876f, + -0.466826f, 0.0298762f, -0.0331735f, -0.0109056f, 0.0114862f, + 0.00396703f, 0.0385985f, -0.0587946f, 0.821079f, 0.0582033f, + 0.349156f, 1.03529f, -0.407036f, 0.200308f, -0.265649f, + -0.104567f, 0.161149f, -0.0717528f, -0.0112724f, 0.0681578f, + 0.103809f, -0.0807997f, 0.0316814f, -0.332323f, 0.112254f, + -0.163981f, 0.118988f, -0.777055f, -1.34047f, -0.910482f, + 0.74599f, -0.59633f, 0.165649f, -0.594998f, 0.0845802f, + 0.00440975f, 0.122606f, -0.463991f, 0.418502f, -0.339126f, + 1.41847f, -0.109594f, -0.411879f, -0.444865f, -0.0404821f, + -0.0607352f, -0.663753f, -0.724327f, -0.138642f, 0.834144f, + -0.811695f, -0.930264f, 0.150993f, -0.325565f, 0.0615853f, + -0.473993f, 0.0966587f, 0.315197f, 1.0345f, 0.35441f, + 0.703234f, -0.335715f, 0.783153f, 0.467976f, -0.0234736f, + 0.549724f, 0.539107f, -0.510182f, -0.154442f, 0.0126656f, + 1.66711f, 0.884555f, 0.118675f, -0.341705f, 0.195316f, + -0.0366564f, -0.619244f, -0.634092f, -0.559951f, 0.0564255f, + 0.765917f, 0.0510238f, 0.0667615f, 0.0699302f, -0.0351751f, + -0.0484402f, -0.000792665f, -0.10775f, -0.337121f, -0.983947f, + 0.517793f, 1.34977f, -0.567602f, 0.129921f, -0.443722f, + -0.276277f, -0.501404f, -0.183234f, -0.553055f, -0.447434f, + -0.35529f, -0.0444689f, 0.0192031f, 0.0372702f, -0.195202f, + -0.020753f, -0.0247035f, 0.420298f, 1.39373f, 0.203699f, + -0.218818f, 0.250734f, -0.0282348f, 0.411986f, -0.262946f, + 0.526339f, 0.242769f, -0.159857f, -0.546788f, -0.0410147f, + 0.954238f, -0.0252765f, 0.639488f, -0.491367f, -0.0572638f, + 0.285763f, -0.45764f, 0.121657f, -1.24374f, -0.372479f, + -0.111521f, 0.194134f, -0.271364f, 0.179678f, 0.121237f, + -0.14305f, -0.205662f, 0.216891f, 0.344568f, -0.523745f, + -1.00908f, 0.180965f, 0.0263031f, -0.0556144f, 0.0831083f, + -0.0623274f, 0.112748f, 0.597137f, -0.502616f, -1.10624f, + -0.0487462f, -1.10744f, -0.125653f, 0.277049f, -0.141329f, + -0.00457003f, -0.161038f, 0.588462f, 0.323317f, 0.49762f, + 0.477561f, 0.901705f, -0.264511f, 0.256557f, 0.076023f, + -0.0460696f, 0.0830666f, -0.0651269f, -0.881245f, -0.285999f, + 0.53127f, 0.914533f, 0.0505795f, -0.3054f, -0.0988696f, + -0.0658403f, 0.15979f, -0.453316f, -0.824834f, -0.280222f, + -0.686952f, -0.0768344f, -1.12235f, -0.815408f, 0.0202134f, + -0.111892f, 0.0847659f, -0.18763f, 0.597782f, 0.364016f + }; + +static const float + av1_fp_simple_motion_search_term_none_hiddenlayer_0_bias_32[] = { + -1.541f, -0.00935641f, -1.50754f, -0.638648f, -0.679403f, + -0.0387804f, -0.714791f, -1.69522f, 0.435677f, -1.5846f, + 0.108788f, 0.614982f, 0.111048f, -0.465826f, -0.611358f, + 0.637197f, 0.929621f, -1.20889f, 0.954558f, 0.716529f + }; + +static const float av1_fp_simple_motion_search_term_none_logits_kernel_32[] = { + 0.396195f, -0.791364f, -0.881893f, 1.0542069f, 0.772562f, + 0.60815647f, 1.117405f, -1.272638f, 0.483183f, -0.917147f, + 0.690799f, -0.601466f, -0.545536f, -0.416353f, -0.927874f, + 0.972198f, -0.3770457f, 0.542694f, -0.591889f, 0.464565f +}; + +static const float av1_fp_simple_motion_search_term_none_logits_bias_32[] = { + -0.590318f +}; + +static const NN_CONFIG av1_fp_simple_motion_search_term_none_nn_config_32 = { + NUM_FEATURES_32, + NUM_LOGITS_32, + NUM_HIDDEN_LAYERS_32, + { + NUM_LAYER_0_UNITS_32, + }, + { + av1_fp_simple_motion_search_term_none_hiddenlayer_0_kernel_32, + av1_fp_simple_motion_search_term_none_logits_kernel_32, + }, + { + av1_fp_simple_motion_search_term_none_hiddenlayer_0_bias_32, + av1_fp_simple_motion_search_term_none_logits_bias_32, + }, +}; + +#undef NUM_HIDDEN_LAYERS_32 +#undef NUM_FEATURES_32 +#undef NUM_LAYER_0_UNITS_32 +#undef NUM_LOGITS_32 + +#define NUM_HIDDEN_LAYERS_16 1 +#define NUM_FEATURES_16 20 +#define NUM_LAYER_0_UNITS_16 24 +#define NUM_LOGITS_16 1 + +static const float + av1_fp_simple_motion_search_term_none_hiddenlayer_0_kernel_16[] = { + -0.315922f, 0.74455f, -0.0196939f, 0.238336f, 0.288554f, + 0.0845902f, -0.0121831f, 0.455303f, 0.0235902f, 0.218997f, + -0.0445164f, 0.0752211f, 0.0539915f, -0.0439682f, -0.397139f, + -0.0030004f, -0.106365f, 0.845384f, 0.684638f, -0.965702f, + 0.307643f, -0.0433377f, -0.0644826f, -0.214946f, -0.44467f, + 0.142967f, 0.0109982f, -0.344458f, -0.42947f, 0.269175f, + -0.88534f, -0.28077f, -1.36018f, -0.33725f, -0.0885953f, + -0.123887f, 0.218107f, -0.0759977f, 0.739124f, 0.684048f, + 0.577964f, -0.328481f, -0.247837f, 0.00546713f, 0.191895f, + -0.145274f, 0.320121f, -0.482379f, 0.534585f, -0.1582f, + 0.944784f, 0.944665f, 0.0494451f, -0.0399724f, -0.170375f, + -0.0869746f, 0.106216f, -0.120556f, -1.57849f, -0.752895f, + 0.424454f, -0.0269515f, 0.00398589f, 0.214165f, -0.142986f, + 0.199223f, 0.049624f, -0.116783f, -0.648119f, -0.311599f, + 0.122629f, -0.0338422f, 0.345092f, -0.408254f, 0.601037f, + -0.00146985f, 0.00133926f, 0.0392668f, -0.931156f, 0.31429f, + -0.150243f, 0.0755763f, -0.32177f, 0.258521f, -0.104078f, + -0.144506f, 0.0199566f, -0.454723f, -0.292959f, -0.0953681f, + -1.24843f, 0.446814f, -0.311363f, 0.0590878f, -0.0568717f, + -0.421585f, 0.179852f, 0.668763f, 0.48914f, 0.290584f, + -1.14053f, -1.37576f, 0.420112f, -0.158582f, 0.268231f, + 0.252999f, 0.276423f, 0.529033f, 0.141127f, 0.702762f, + 0.181407f, -0.0279289f, -0.0194757f, 0.0752152f, -0.136963f, + 0.00902489f, 0.125334f, 0.0680212f, -0.370449f, 0.438003f, + -0.600869f, 0.154209f, -0.36306f, -0.484209f, 0.140093f, + 0.0743079f, -0.143317f, 0.0442872f, 0.272089f, 0.601531f, + 1.20687f, -0.280695f, 0.222235f, -0.0106747f, -0.017026f, + 0.204008f, -0.0316111f, -0.64679f, -0.866749f, -0.774231f, + 0.306231f, -0.0940114f, -0.56555f, -0.34399f, 0.425142f, + 0.424064f, -0.50189f, -0.146558f, 0.544899f, 0.141728f, + 1.14592f, -0.0124826f, 0.111613f, -0.0862228f, 0.0211737f, + 0.0614017f, 0.0245077f, -0.454523f, -0.0766391f, -0.436808f, + 0.251409f, -0.13354f, -0.242447f, -0.311807f, -0.844505f, + -0.671486f, 0.0946297f, 0.241702f, 0.856521f, 0.529763f, + -0.869772f, -0.0016341f, 0.14511f, 0.0136254f, -0.0359721f, + -0.0454713f, 0.00664495f, 0.0373555f, 0.653991f, -0.075867f, + -0.102728f, -0.947685f, -0.119479f, -0.145413f, 0.148364f, + 0.310885f, -0.266837f, 0.354087f, 0.299469f, 0.603911f, + 0.257161f, 0.0190527f, 0.152862f, -0.0987196f, -0.293369f, + 0.139026f, -0.128421f, 0.0505933f, -0.703803f, 1.08628f, + -0.562294f, -0.818943f, 0.102178f, 0.727399f, -0.228433f, + 0.484057f, 0.0595919f, -0.0559087f, -0.549447f, 0.176168f, + 1.41744f, -0.126284f, 0.0987251f, -0.00123073f, 0.00510827f, + 0.105209f, 0.0671775f, -0.438525f, 0.211028f, -0.782459f, + 0.286411f, -0.459887f, 0.0633669f, 0.329958f, -0.0736945f, + 0.45188f, -0.2447f, 0.676601f, 0.600321f, -0.0336198f, + 0.108531f, 0.0452834f, -0.0848577f, 0.0731281f, 1.32381f, + -0.118349f, 0.129497f, -0.840938f, -1.45444f, -0.559047f, + -0.248109f, -0.491559f, -0.139812f, 0.175964f, 0.168687f, + 0.123031f, 0.201625f, 0.422849f, 0.34436f, 0.0426694f, + 0.558045f, -0.246772f, 0.679483f, -0.0959578f, -0.102879f, + 0.391029f, 0.280906f, 0.0867408f, -1.10932f, 0.402526f, + -0.227285f, 0.336087f, -0.237765f, 0.185619f, -0.309732f, + 0.0781132f, -0.0234955f, 0.0828806f, 0.19966f, -0.241288f, + -0.224634f, 0.0638918f, -0.143521f, -0.0206692f, -0.27131f, + 0.973051f, 1.12031f, 0.262846f, 0.471585f, 0.105231f, + -0.386434f, -0.355846f, 0.7359f, 0.567308f, 0.130768f, + 0.242369f, -0.0272523f, -0.118436f, 0.374145f, 0.24802f, + -1.00186f, -0.0241195f, 0.0140446f, 0.0202831f, 0.163197f, + 0.0399298f, -0.00912791f, -0.280572f, -0.309893f, -0.644495f, + 0.243838f, 0.731391f, 0.0725078f, 0.350308f, -0.136691f, + 0.208814f, 0.0218567f, -0.0805393f, -0.18681f, -0.214638f, + 0.273354f, -0.355047f, 0.242748f, 0.472951f, -0.202705f, + 0.405247f, 0.161622f, -0.284883f, -1.31181f, -0.661056f, + -0.248219f, -0.827307f, 0.289221f, 0.660529f, 0.48563f, + 0.407366f, 0.0327303f, -0.0610309f, -0.647064f, 0.0899991f, + 0.376267f, 1.27555f, 0.0264175f, 0.153931f, 1.07345f, + 0.0715052f, 0.174473f, 0.01322f, -0.715723f, 0.113909f, + 0.100968f, -0.457287f, -0.672022f, -0.20532f, 0.895176f, + 0.357034f, 0.5413f, 0.918393f, -0.455f, -0.499617f, + -1.21799f, 0.0634338f, 0.144944f, -0.106715f, 0.0227713f, + -0.0203213f, 0.030851f, -0.0726756f, 0.589192f, -0.060841f, + -0.198521f, 0.497179f, -0.0591156f, -0.135466f, -0.132638f, + -0.181333f, -0.332358f, 0.0349959f, 0.212885f, -0.536206f, + -0.425009f, -0.035525f, 0.0384449f, 0.0360549f, -0.0383953f, + -0.0263281f, -0.0228435f, 1.11771f, 0.928061f, -0.163923f, + -0.327868f, -0.894518f, 0.00448907f, 0.0805977f, 0.329559f, + 0.157429f, 0.292729f, 0.497688f, 0.188659f, 0.203724f, + -1.26001f, -0.0392533f, -0.0566088f, 0.000859925f, 0.125254f, + 0.054261f, 0.0357295f, -0.393813f, -0.275944f, 0.299657f, + -0.211421f, 0.038172f, -0.439829f, -0.913949f, 0.35642f, + 0.865473f, -0.472033f, -0.752376f, 0.995255f, 0.417965f, + -0.680645f, 0.0622027f, 0.128878f, -0.0357859f, 0.0793577f, + 0.203629f, -0.0600867f, 0.0512268f, 0.528584f, 0.23889f, + 0.38255f, -0.216407f, -0.0338828f, 0.0328103f, -0.885678f, + -0.716634f, 0.438663f, 0.320841f, -0.119656f, 0.626092f, + 0.8526f, -0.0325005f, -0.0275416f, -0.171131f, 0.0260563f, + -0.0162027f, 0.0879367f, -0.340473f, 0.0220265f, -0.1731f, + 0.512539f, 0.587822f, -0.175619f, 0.177215f, -0.35458f, + -0.159059f, -0.423754f, 0.0198413f, -0.336208f, -0.359052f, + -1.50819f, 0.0628184f, 0.054506f, 0.0048834f, 0.361657f, + 0.00986886f, -0.0721521f, -0.256765f, 1.41173f, 0.376196f, + -0.0783331f, 0.174803f, -0.00240091f, -0.306571f, -0.304654f, + -0.0348377f, 0.115569f, -0.20359f, -0.162341f, -0.0443526f, + -0.848317f, -0.228167f, 0.699534f, 0.482092f, -0.0921484f, + -0.172425f, -0.0610094f, -0.188327f, 0.836209f, 0.541725f + }; + +static const float + av1_fp_simple_motion_search_term_none_hiddenlayer_0_bias_16[] = { + -0.388147f, -0.0868767f, 0.702129f, 0.376659f, -0.709988f, 0.496603f, + -0.238442f, -1.35761f, -0.391887f, 0.235468f, -0.327982f, 0.731842f, + 1.0949f, -0.789218f, -0.881452f, 0.514341f, 0.727894f, -0.494498f, + -1.32304f, -1.22643f, -0.294287f, -1.3974f, -0.128148f, -0.0956137f + }; + +static const float av1_fp_simple_motion_search_term_none_logits_kernel_16[] = { + 0.456147f, 0.248707f, -0.5205241f, -0.1506567f, 0.388359f, -0.6074409f, + -0.4719775f, -0.733864f, 0.5588447f, -0.4021345f, -1.140733f, -0.73399f, + -0.4299591f, 0.450688f, 0.817564f, -0.265486f, -0.3525806f, 0.55188314f, + 1.365457f, 1.180764f, 0.587772f, -0.870683f, 0.818839f, 0.318488f +}; + +static const float av1_fp_simple_motion_search_term_none_logits_bias_16[] = { + -0.1046478f +}; + +static const NN_CONFIG av1_fp_simple_motion_search_term_none_nn_config_16 = { + NUM_FEATURES_16, + NUM_LOGITS_16, + NUM_HIDDEN_LAYERS_16, + { + NUM_LAYER_0_UNITS_16, + }, + { + av1_fp_simple_motion_search_term_none_hiddenlayer_0_kernel_16, + av1_fp_simple_motion_search_term_none_logits_kernel_16, + }, + { + av1_fp_simple_motion_search_term_none_hiddenlayer_0_bias_16, + av1_fp_simple_motion_search_term_none_logits_bias_16, + }, +}; + +#undef NUM_HIDDEN_LAYERS_16 +#undef NUM_FEATURES_16 +#undef NUM_LAYER_0_UNITS_16 +#undef NUM_LOGITS_16 + +#define NUM_HIDDEN_LAYERS_8 1 +#define NUM_FEATURES_8 20 +#define NUM_LAYER_0_UNITS_8 16 +#define NUM_LOGITS_8 1 + +static const float + av1_fp_simple_motion_search_term_none_hiddenlayer_0_kernel_8[] = { + -1.11024f, -0.530449f, -0.164768f, 0.675431f, 0.456155f, + 0.711099f, -0.248095f, 0.112132f, -0.131481f, 0.234457f, + 0.128073f, 0.306214f, 0.175471f, 0.220189f, -0.270533f, + 0.293534f, -0.0795547f, 0.234901f, -0.191754f, 0.101171f, + -0.108621f, 0.395477f, -0.529459f, -0.354854f, -0.941334f, + -0.237689f, 0.39357f, 0.527129f, 0.174333f, -0.00520422f, + 1.22219f, -0.21815f, 0.0866816f, -0.29591f, -0.212968f, + 0.00431436f, -0.295382f, -0.582317f, -0.284654f, 0.486427f, + -0.202448f, -0.0421883f, -0.116346f, -0.345832f, -0.0471637f, + -0.149954f, -0.0969526f, -0.59491f, 0.594364f, 0.298285f, + -1.33301f, 0.149562f, 0.097433f, 0.157641f, -0.231132f, + -0.0191656f, 0.149396f, 0.811553f, 1.07336f, 0.140674f, + 1.02134f, 0.455909f, -0.0548795f, 0.0459996f, -0.0589837f, + -0.116328f, -0.607502f, -0.232595f, -0.517977f, -0.325901f, + 1.35047f, -0.148698f, 0.0313182f, 0.181634f, 0.06539f, + 0.00820322f, 0.0522113f, -1.06071f, -0.817999f, -0.527422f, + -1.39175f, -0.110088f, 0.0858626f, -0.247541f, 0.29043f, + 1.13767f, 0.185834f, 0.390613f, -0.501175f, -0.214176f, + -0.256376f, 0.496687f, 0.240471f, 0.218852f, 0.513543f, + 0.400559f, -0.249168f, -0.752987f, 0.430491f, -0.72299f, + 0.339754f, 0.396623f, -0.0638322f, 0.353122f, 0.355662f, + -0.0704821f, 0.195448f, 0.179396f, 0.486533f, 0.0815535f, + -0.503726f, -0.000321223f, 0.501591f, -0.117849f, 0.217667f, + -0.123391f, -0.4026f, 0.149756f, -0.0359276f, -0.0990213f, + -0.215278f, -0.293649f, 0.301629f, -0.11081f, -0.206725f, + -0.00147108f, 0.363644f, -0.430092f, 0.169524f, 0.116091f, + -0.583605f, -0.0974948f, 0.253256f, 0.22648f, 0.136902f, + -0.882541f, -0.75078f, -0.0629343f, 0.411035f, 0.265742f, + -0.360904f, -0.899324f, 0.605871f, 0.0318372f, 0.0735312f, + -0.00960722f, 0.691249f, 0.127449f, -0.133021f, -0.0793589f, + 0.665591f, -0.0682262f, -0.0437626f, 0.0783621f, 2.25727f, + 0.126529f, -0.0320763f, -0.261759f, -1.19987f, 0.216295f, + -0.253886f, -0.642908f, 0.1865f, 0.00299179f, 0.0246782f, + -0.00750628f, 0.566367f, 0.99916f, -0.0209625f, 0.273254f, + 1.09724f, 0.30026f, 0.21585f, -0.0276715f, 0.338996f, + 0.129884f, -0.00628438f, 0.0461783f, -1.36378f, -0.394756f, + -0.395261f, 0.215928f, 0.252803f, -0.207108f, -0.0506214f, + -0.0138889f, 0.124197f, -0.0522996f, 0.533803f, -0.25729f, + -0.463514f, 0.128322f, -1.04751f, -0.605498f, -0.107235f, + -0.00813289f, 0.539742f, -0.0524178f, 0.272101f, 0.151935f, + 0.607511f, -0.0608427f, 0.36342f, 0.0999134f, 0.69712f, + -0.152471f, 0.364244f, 0.410644f, 0.312606f, 0.405679f, + -0.371656f, -0.0492209f, -0.148911f, 0.214996f, -0.274749f, + -0.0372888f, 0.079023f, -0.429136f, -1.30393f, -0.833824f, + -1.31373f, -0.445343f, 0.526917f, 1.30569f, -0.0626746f, + 0.282353f, -0.28552f, 0.28084f, -0.234934f, 0.227076f, + 1.09919f, 0.33248f, -0.114933f, 0.40629f, 0.331031f, + 0.245334f, -0.0318782f, 0.00735305f, -1.58715f, 0.126443f, + -0.09472f, -0.182152f, 0.311673f, -0.186136f, 0.817743f, + 0.928961f, 0.117334f, -0.373644f, -0.0797864f, 0.205565f, + 0.0789797f, 0.0757131f, -0.152409f, 0.30301f, -0.0170824f, + -0.194496f, 0.485547f, 0.370124f, -0.802044f, -0.789671f, + 0.669258f, 0.55082f, -0.438853f, 0.0597597f, -0.0148101f, + -0.41603f, 0.0486339f, -0.464523f, -0.413725f, 0.00907629f, + 0.70351f, -0.136422f, -0.145957f, -0.0626726f, -0.115773f, + -0.333937f, 0.135474f, -0.379598f, -0.134422f, 0.227595f, + 0.908927f, 0.759504f, -0.0088258f, -0.349333f, 0.122667f, + -0.682175f, 0.2201f, -0.332003f, -0.44433f, -0.620308f, + -1.36716f, -0.0167907f, -0.538969f, 0.256824f, -0.0706724f, + -0.0392471f, -0.156312f, 0.153699f, 1.41967f, 0.0434739f, + 0.428178f, -0.0714879f, 0.0912104f, 0.00687985f, 0.341789f, + 0.217381f, 0.128288f, 0.0286751f, 0.527344f, -0.428139f, + 0.60908f, 1.02074f, -0.0977894f, 0.158067f, 0.28958f, + -0.065152f, 0.120616f, -0.882976f, -1.10413f, -1.37497f + }; + +static const float + av1_fp_simple_motion_search_term_none_hiddenlayer_0_bias_8[] = { + 1.37086f, -1.61858f, -1.32395f, 0.276031f, -0.124696f, -1.71489f, + -1.68429f, 1.79103f, -0.335306f, -1.81523f, 0.841083f, -0.542628f, + -1.82168f, 0.459829f, 0.0949306f, 0.918486f + }; + +static const float av1_fp_simple_motion_search_term_none_logits_kernel_8[] = { + -0.283418f, -0.444453f, 0.4977782f, -0.4138758f, 0.41890771f, 0.22149438f, + 0.545079f, -0.729164f, 0.619389f, 0.5169534f, -0.4236282f, 0.7304213f, + 0.531938f, -0.14828f, 0.75119f, -0.464074f +}; + +static const float av1_fp_simple_motion_search_term_none_logits_bias_8[] = { + -2.22338f +}; + +static const NN_CONFIG av1_fp_simple_motion_search_term_none_nn_config_8 = { + NUM_FEATURES_8, + NUM_LOGITS_8, + NUM_HIDDEN_LAYERS_8, + { + NUM_LAYER_0_UNITS_8, + }, + { + av1_fp_simple_motion_search_term_none_hiddenlayer_0_kernel_8, + av1_fp_simple_motion_search_term_none_logits_kernel_8, + }, + { + av1_fp_simple_motion_search_term_none_hiddenlayer_0_bias_8, + av1_fp_simple_motion_search_term_none_logits_bias_8, + }, +}; + +#undef NUM_HIDDEN_LAYERS_8 +#undef NUM_FEATURES_8 +#undef NUM_LAYER_0_UNITS_8 +#undef NUM_LOGITS_8 + +static const float av1_fp_simple_motion_search_term_none_thresh_32 = + -2.2884985045792563f; +static const float av1_fp_simple_motion_search_term_none_thresh_16 = + -1.6656874577527165f; +static const float av1_fp_simple_motion_search_term_none_thresh_8 = + -3.608804354309157f; #ifdef __cplusplus } // extern "C" diff --git a/third_party/aom/av1/encoder/partition_strategy.c b/third_party/aom/av1/encoder/partition_strategy.c new file mode 100644 index 0000000000..2dace6c167 --- /dev/null +++ b/third_party/aom/av1/encoder/partition_strategy.c @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2019, 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 + +#include "aom_ports/system_state.h" + +#include "av1/common/enums.h" +#include "av1/common/reconinter.h" + +#include "av1/encoder/encoder.h" +#include "av1/encoder/partition_model_weights.h" +#include "av1/encoder/partition_strategy.h" +#include "av1/encoder/rdopt.h" + +// Performs a simple_motion_search with a single reference frame and extract +// the variance of residues. Here features is assumed to be a length 6 array. +// After this function is called, we will store the following in to features: +// features[0] = log(1 + dc_q**2/256) +// features[1] = log(1 + variance_of_residue) +// for i in [2, 3, 4, 5]: +// features[i] = log(1 + variance_of_residue_in_block[i]/variance_of_residue) +static void get_res_var_features(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, + int mi_col, BLOCK_SIZE bsize, + float *features) { + // TODO(chiyotsai@google.com): The data this model trained on did not also use + // SIMPLE_TRANSLATION to build the inter_predictor. Retraining and tuning the + // model with the correct data should give better performance. + assert(mi_size_wide[bsize] == mi_size_high[bsize]); + + MACROBLOCKD *xd = &x->e_mbd; + + // Perform a single motion search in Y_PLANE to make a prediction + const int use_subpixel = 0; + + // Start getting the features + int f_idx = 0; + + // Q_INDEX + const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); + aom_clear_system_state(); + features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f); + + // VARIANCE + unsigned int sse = 0; + unsigned int var = 0; + const MV ref_mv_full = { .row = 0, .col = 0 }; + av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, ref_mv_full, + use_subpixel, &sse, &var); + aom_clear_system_state(); + features[f_idx++] = logf(1.0f + (float)var); + + // Regional + const uint8_t *src = x->plane[0].src.buf; + const int src_stride = x->plane[0].src.stride; + const uint8_t *dst = xd->plane[0].dst.buf; + const int dst_stride = xd->plane[0].dst.stride; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT); + int r_idx = 0; + for (r_idx = 0; r_idx < 4; r_idx++) { + const int x_idx = (r_idx & 1) * bw / 2; + const int y_idx = (r_idx >> 1) * bh / 2; + const int src_offset = y_idx * src_stride + x_idx; + const int dst_offset = y_idx * dst_stride + x_idx; + const unsigned int sub_var = cpi->fn_ptr[subsize].vf( + src + src_offset, src_stride, dst + dst_offset, dst_stride, &sse); + aom_clear_system_state(); + const float var_ratio = (1.0f + (float)sub_var) / (4.0f + (float)var); + features[f_idx++] = var_ratio; + } +} + +void av1_simple_motion_search_based_split( + AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, int mi_col, + BLOCK_SIZE bsize, int *partition_none_allowed, int *partition_horz_allowed, + int *partition_vert_allowed, int *do_rectangular_split, + int *do_square_split) { + const NN_CONFIG *nn_config = NULL; + float split_only_thresh = 0.0f; + if (bsize == BLOCK_128X128) { + nn_config = &av1_simple_motion_search_based_split_nn_config_128; + split_only_thresh = av1_simple_motion_search_based_split_thresh_128; + } else if (bsize == BLOCK_64X64) { + nn_config = &av1_simple_motion_search_based_split_nn_config_64; + split_only_thresh = av1_simple_motion_search_based_split_thresh_64; + } else if (bsize == BLOCK_32X32) { + nn_config = &av1_simple_motion_search_based_split_nn_config_32; + split_only_thresh = av1_simple_motion_search_based_split_thresh_32; + } else if (bsize == BLOCK_16X16) { + nn_config = &av1_simple_motion_search_based_split_nn_config_16; + split_only_thresh = av1_simple_motion_search_based_split_thresh_16; + } else if (bsize == BLOCK_8X8) { + // Disable BLOCK_8X8 for now +#if !CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 + nn_config = &av1_simple_motion_search_based_split_nn_config_8; + split_only_thresh = av1_simple_motion_search_based_split_thresh_8; +#endif + } else { + assert(0 && "Unexpected block size in simple_motion_based_split"); + } + if (nn_config) { + float features[6] = { 0 }; + float score = 0; + get_res_var_features(cpi, x, mi_row, mi_col, bsize, features); + av1_nn_predict(features, nn_config, &score); + + if (score > split_only_thresh) { + *partition_none_allowed = 0; + *partition_horz_allowed = 0; + *partition_vert_allowed = 0; + *do_rectangular_split = 0; + } + // TODO(Venkat): Experiment to skip only rectangular/extended parititions + if (cpi->sf.simple_motion_search_split_only >= 2) { + if (score < -split_only_thresh) *do_square_split = 0; + } + } +} + +// Given a list of ref frames in refs, performs simple_motion_search on each of +// the refs and returns the ref with the smallest sse. Returns -1 if none of the +// ref in the list is available. Also stores the best sse and var in best_sse, +// best_var, respectively. If save_mv_code is -1, don't update mv_ref_fulls in +// pc_tree. If save_mv_code is between 0 and 3, update mv_ref_fulls under +// pc_tree->split[i]. If save_mv_code is 4, update mv_ref_fulls under pc_tree. +static int simple_motion_search_get_best_ref( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, const int *const refs, int num_refs, + int use_subpixel, int save_mv_code, unsigned int *best_sse, + unsigned int *best_var) { + // TODO(chiyotsai@google.com): The calculation of variance currently uses + // bsize, so we might take area outside of the image into account. We need to + // modify the SIMD functions to fix this later. + const AV1_COMMON *const cm = &cpi->common; + int best_ref = -1; + + if (mi_col >= cm->mi_cols || mi_row >= cm->mi_rows) { + // If the whole block is outside of the image, set the var and sse to 0. + *best_var = 0; + *best_sse = 0; + + return best_ref; + } + + // Otherwise do loop through the reference frames and find the one with the + // minimum SSE + const MACROBLOCKD *xd = &x->e_mbd; + const MV *mv_ref_fulls = pc_tree->mv_ref_fulls; + + const int num_planes = 1; + + *best_sse = INT_MAX; + + for (int ref_idx = 0; ref_idx < num_refs; ref_idx++) { + const int ref = refs[ref_idx]; + + if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref]) { + unsigned int curr_sse = 0, curr_var = 0; + av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, + mv_ref_fulls[ref], num_planes, use_subpixel); + curr_var = cpi->fn_ptr[bsize].vf( + x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].dst.buf, + xd->plane[0].dst.stride, &curr_sse); + if (curr_sse < *best_sse) { + *best_sse = curr_sse; + *best_var = curr_var; + best_ref = ref; + } + + const int new_mv_row = x->best_mv.as_mv.row / 8; + const int new_mv_col = x->best_mv.as_mv.col / 8; + if (save_mv_code == 4) { + pc_tree->mv_ref_fulls[ref].row = new_mv_row; + pc_tree->mv_ref_fulls[ref].col = new_mv_col; + } else if (save_mv_code >= 0 && save_mv_code < 4) { + // Propagate the new motion vectors to a lower level + pc_tree->split[save_mv_code]->mv_ref_fulls[ref].row = new_mv_row; + pc_tree->split[save_mv_code]->mv_ref_fulls[ref].col = new_mv_col; + } else { + assert(save_mv_code == -1 && + "Unknown code in simple_motion_search_get_best_ref."); + } + } + } + + return best_ref; +} + +// Performs fullpixel simple_motion_search with LAST_FRAME and ALTREF_FRAME on +// each subblock and extract the variance and sse of residues. Then store the +// var and sse from each partition subblock to features. The DC qindex is also +// stored in features. +// Here features is assumed to be a length 19 array. +// After this function is called, we will store the following to features: +// features[0:17] = var and sse from subblocks +// features[18] = DC q_index +static void simple_motion_search_prune_part_features( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, float *features) { + // TODO(chiyotsai@google.com): Cache the result of the motion search from the + // larger bsize. + const int w_mi = mi_size_wide[bsize]; + const int h_mi = mi_size_high[bsize]; + int f_idx = 0; + assert(mi_size_wide[bsize] == mi_size_high[bsize]); + assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME] || + cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]); + + // Setting up motion search + const int ref_list[] = { LAST_FRAME, ALTREF_FRAME }; + const int num_refs = 2; + const int use_subpixel = 1; + + unsigned int int_features[FEATURE_SIZE_SMS_PRUNE_PART - 1]; + + // Doing whole block first to update the mv + simple_motion_search_get_best_ref( + cpi, x, pc_tree, mi_row, mi_col, bsize, ref_list, num_refs, use_subpixel, + 4, &int_features[f_idx], &int_features[f_idx + 1]); + f_idx += 2; + + // Split subblocks + BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT); + int r_idx = 0; + for (r_idx = 0; r_idx < 4; r_idx++) { + const int sub_mi_col = mi_col + (r_idx & 1) * w_mi / 2; + const int sub_mi_row = mi_row + (r_idx >> 1) * h_mi / 2; + + simple_motion_search_get_best_ref( + cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, + use_subpixel, r_idx, &int_features[f_idx], &int_features[f_idx + 1]); + f_idx += 2; + } + + // Horz subblocks + subsize = get_partition_subsize(bsize, PARTITION_HORZ); + for (r_idx = 0; r_idx < 2; r_idx++) { + const int sub_mi_col = mi_col + 0; + const int sub_mi_row = mi_row + r_idx * h_mi / 2; + + simple_motion_search_get_best_ref( + cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, + use_subpixel, -1, &int_features[f_idx], &int_features[f_idx + 1]); + + f_idx += 2; + } + + // Vert subblock + subsize = get_partition_subsize(bsize, PARTITION_VERT); + for (r_idx = 0; r_idx < 2; r_idx++) { + const int sub_mi_col = mi_col + r_idx * w_mi / 2; + const int sub_mi_row = mi_row + 0; + + simple_motion_search_get_best_ref( + cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, + use_subpixel, -1, &int_features[f_idx], &int_features[f_idx + 1]); + + f_idx += 2; + } + + aom_clear_system_state(); + for (int idx = 0; idx < f_idx; idx++) { + features[idx] = logf(1.0f + (float)int_features[idx]); + } + + const MACROBLOCKD *xd = &x->e_mbd; + set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize); + + // Q_INDEX + const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); + features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f); + + // Neighbor stuff + const int has_above = !!xd->above_mbmi; + const int has_left = !!xd->left_mbmi; + const BLOCK_SIZE above_bsize = has_above ? xd->above_mbmi->sb_type : bsize; + const BLOCK_SIZE left_bsize = has_left ? xd->left_mbmi->sb_type : bsize; + features[f_idx++] = (float)has_above; + features[f_idx++] = (float)mi_size_wide_log2[above_bsize]; + features[f_idx++] = (float)mi_size_high_log2[above_bsize]; + features[f_idx++] = (float)has_left; + features[f_idx++] = (float)mi_size_wide_log2[left_bsize]; + features[f_idx++] = (float)mi_size_high_log2[left_bsize]; + + assert(f_idx == FEATURE_SIZE_SMS_PRUNE_PART); +} + +void av1_simple_motion_search_prune_part( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, int *partition_none_allowed, + int *partition_horz_allowed, int *partition_vert_allowed, + int *do_square_split, int *do_rectangular_split, int *prune_horz, + int *prune_vert, float *features, int *valid) { + const AV1_COMMON *const cm = &cpi->common; + // Get model parameters + const NN_CONFIG *nn_config = NULL; + const float *prune_thresh = NULL, *only_thresh = NULL; + const float *ml_mean = NULL, *ml_std = NULL; + float normalized_features[FEATURE_SIZE_SMS_PRUNE_PART] = { 0.0f }; + + if (bsize == BLOCK_128X128) { + nn_config = &av1_simple_motion_search_prune_part_nn_config_128; + ml_mean = av1_simple_motion_search_prune_part_mean_128; + ml_std = av1_simple_motion_search_prune_part_std_128; + prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_128; + only_thresh = av1_simple_motion_search_prune_part_only_thresh_128; + } else if (bsize == BLOCK_64X64) { + nn_config = &av1_simple_motion_search_prune_part_nn_config_64; + ml_mean = av1_simple_motion_search_prune_part_mean_64; + ml_std = av1_simple_motion_search_prune_part_std_64; + prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_64; + only_thresh = av1_simple_motion_search_prune_part_only_thresh_64; + } else if (bsize == BLOCK_32X32) { + nn_config = &av1_simple_motion_search_prune_part_nn_config_32; + ml_mean = av1_simple_motion_search_prune_part_mean_32; + ml_std = av1_simple_motion_search_prune_part_std_32; + prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_32; + only_thresh = av1_simple_motion_search_prune_part_only_thresh_32; + } else if (bsize == BLOCK_16X16) { + nn_config = &av1_simple_motion_search_prune_part_nn_config_16; + ml_mean = av1_simple_motion_search_prune_part_mean_16; + ml_std = av1_simple_motion_search_prune_part_std_16; + prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_16; + only_thresh = av1_simple_motion_search_prune_part_only_thresh_16; + } else if (bsize == BLOCK_8X8) { + nn_config = &av1_simple_motion_search_prune_part_nn_config_8; + ml_mean = av1_simple_motion_search_prune_part_mean_8; + ml_std = av1_simple_motion_search_prune_part_std_8; + prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_8; + only_thresh = av1_simple_motion_search_prune_part_only_thresh_8; + } else { + assert(0 && "Unexpected block size in simple_motion_prune_part"); + } + + // If there is no valid threshold, return immediately. + if (!nn_config || (prune_thresh[PARTITION_HORZ] == 0.0f && + prune_thresh[PARTITION_VERT] == 0.0f)) { + return; + } + if (bsize < BLOCK_8X8) { + return; + } + + // Get features + simple_motion_search_prune_part_features(cpi, x, pc_tree, mi_row, mi_col, + bsize, features); + *valid = 1; + for (int f_idx = 0; f_idx < FEATURE_SIZE_SMS_PRUNE_PART; f_idx++) { + normalized_features[f_idx] = + (features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx]; + } + + // Get probabilities + float scores[EXT_PARTITION_TYPES] = { 0.0f }, + probs[EXT_PARTITION_TYPES] = { 0.0f }; + const int num_classes = (bsize == BLOCK_128X128 || bsize == BLOCK_8X8) + ? PARTITION_TYPES + : EXT_PARTITION_TYPES; + + av1_nn_predict(normalized_features, nn_config, scores); + aom_clear_system_state(); + + av1_nn_softmax(scores, probs, num_classes); + + // Determine if we should prune rectangular partitions. + if (cpi->sf.simple_motion_search_prune_rect && !frame_is_intra_only(cm) && + (*partition_horz_allowed || *partition_vert_allowed) && + bsize >= BLOCK_8X8 && !av1_superres_scaled(cm)) { + *prune_horz = probs[PARTITION_HORZ] <= prune_thresh[PARTITION_HORZ]; + *prune_vert = probs[PARTITION_VERT] <= prune_thresh[PARTITION_VERT]; + } + + // Silence compiler warnings + (void)only_thresh; + (void)partition_none_allowed; + (void)do_square_split; + (void)do_rectangular_split; +} + +// Early terminates PARTITION_NONE using simple_motion_search features and the +// rate, distortion, and rdcost of PARTITION_NONE. This is only called when: +// - The frame is a show frame +// - The frame is not intra only +// - The current bsize is > BLOCK_8X8 +// - blk_row + blk_height/2 < total_rows and blk_col + blk_width/2 < total_cols +void av1_simple_motion_search_early_term_none( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, const RD_STATS *none_rdc, + int *early_terminate, float *simple_motion_features, + int *simple_motion_features_are_valid) { + // TODO(chiyotsai@google.com): There are other features we can extract from + // PARTITION_NONE. Play with this later. + int f_idx = 0; + if (!*simple_motion_features_are_valid) { + simple_motion_search_prune_part_features(cpi, x, pc_tree, mi_row, mi_col, + bsize, simple_motion_features); + *simple_motion_features_are_valid = 1; + } + f_idx = 25; + + simple_motion_features[f_idx++] = logf(1.0f + (float)none_rdc->rate); + simple_motion_features[f_idx++] = logf(1.0f + (float)none_rdc->dist); + simple_motion_features[f_idx++] = logf(1.0f + (float)none_rdc->rdcost); + + assert(f_idx == FEATURE_SIZE_SMS_TERM_NONE); + + const float *ml_mean = NULL; + const float *ml_std = NULL; + const float *ml_model = NULL; + + if (bsize == BLOCK_128X128) { + ml_mean = av1_simple_motion_search_term_none_mean_128; + ml_std = av1_simple_motion_search_term_none_std_128; + ml_model = av1_simple_motion_search_term_none_model_128; + } else if (bsize == BLOCK_64X64) { + ml_mean = av1_simple_motion_search_term_none_mean_64; + ml_std = av1_simple_motion_search_term_none_std_64; + ml_model = av1_simple_motion_search_term_none_model_64; + } else if (bsize == BLOCK_32X32) { + ml_mean = av1_simple_motion_search_term_none_mean_32; + ml_std = av1_simple_motion_search_term_none_std_32; + ml_model = av1_simple_motion_search_term_none_model_32; + } else if (bsize == BLOCK_16X16) { + ml_mean = av1_simple_motion_search_term_none_mean_16; + ml_std = av1_simple_motion_search_term_none_std_16; + ml_model = av1_simple_motion_search_term_none_model_16; + } else { + assert(0 && "Unexpected block size in simple_motion_term_none"); + } + + if (ml_model) { + float score = 0.0f; + for (f_idx = 0; f_idx < FEATURE_SIZE_SMS_TERM_NONE; f_idx++) { + score += ml_model[f_idx] * + (simple_motion_features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx]; + } + score += ml_model[FEATURE_SIZE_SMS_TERM_NONE]; + + if (score >= 0.0f) { + *early_terminate = 1; + } + } +} + +static void firstpass_simple_motion_search_features( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, float *features) { + assert(mi_size_wide[bsize] == mi_size_high[bsize]); + assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME] || + cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]); + + // Setting up motion search + const int ref_list[] = { LAST_FRAME, ALTREF_FRAME }; + const int num_refs = 2; + const int use_subpixel = 0; + + unsigned int int_features[10] = { 0 }; + + int f_idx = 0; + // Doing whole block first to update the mv + simple_motion_search_get_best_ref( + cpi, x, pc_tree, mi_row, mi_col, bsize, ref_list, num_refs, use_subpixel, + 4, &int_features[f_idx], &int_features[f_idx + 1]); + f_idx += 2; + + // Split subblocks + const BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT); + const int w_mi = mi_size_wide[bsize]; + const int h_mi = mi_size_high[bsize]; + for (int r_idx = 0; r_idx < 4; r_idx++) { + const int sub_mi_col = mi_col + (r_idx & 1) * w_mi / 2; + const int sub_mi_row = mi_row + (r_idx >> 1) * h_mi / 2; + + simple_motion_search_get_best_ref( + cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs, + use_subpixel, r_idx, &int_features[f_idx], &int_features[f_idx + 1]); + f_idx += 2; + } + + aom_clear_system_state(); + for (int idx = 0; idx < f_idx; idx++) { + features[idx] = logf(1.0f + (float)int_features[idx]); + } + + const MACROBLOCKD *xd = &x->e_mbd; + set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize); + + // Q_INDEX + const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); + features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f); + + // Neighbor stuff + const int has_above = !!xd->above_mbmi; + const int has_left = !!xd->left_mbmi; + const BLOCK_SIZE above_bsize = has_above ? xd->above_mbmi->sb_type : bsize; + const BLOCK_SIZE left_bsize = has_left ? xd->left_mbmi->sb_type : bsize; + features[f_idx++] = (float)has_above; + features[f_idx++] = (float)mi_size_wide_log2[above_bsize]; + features[f_idx++] = (float)mi_size_high_log2[above_bsize]; + features[f_idx++] = (float)has_left; + features[f_idx++] = (float)mi_size_wide_log2[left_bsize]; + features[f_idx++] = (float)mi_size_high_log2[left_bsize]; +} + +void av1_firstpass_simple_motion_search_early_term(AV1_COMP *const cpi, + MACROBLOCK *x, + PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, + const RD_STATS *none_rdc, + int *do_square_split) { + const NN_CONFIG *nn_config = NULL; + float thresh = 0.0f; + const float *ml_mean = NULL, *ml_std = NULL; + if (bsize == BLOCK_32X32) { + nn_config = &av1_fp_simple_motion_search_term_none_nn_config_32; + ml_mean = av1_fp_simple_motion_search_term_none_mean_32; + ml_std = av1_fp_simple_motion_search_term_none_std_32; + thresh = av1_fp_simple_motion_search_term_none_thresh_32; + } else if (bsize == BLOCK_16X16) { + nn_config = &av1_fp_simple_motion_search_term_none_nn_config_16; + ml_mean = av1_fp_simple_motion_search_term_none_mean_16; + ml_std = av1_fp_simple_motion_search_term_none_std_16; + thresh = av1_fp_simple_motion_search_term_none_thresh_16; + } else if (bsize == BLOCK_8X8) { + nn_config = &av1_fp_simple_motion_search_term_none_nn_config_8; + ml_mean = av1_fp_simple_motion_search_term_none_mean_8; + ml_std = av1_fp_simple_motion_search_term_none_std_8; + thresh = av1_fp_simple_motion_search_term_none_thresh_8; + } else { + assert(0 && + "Unexpected bsize in firstpass_simple_motion_search_early_term"); + return; + } + + float ml_features[FEATURE_SIZE_FP_SMS_TERM_NONE] = { 0.0f }; + + firstpass_simple_motion_search_features(cpi, x, pc_tree, mi_row, mi_col, + bsize, ml_features); + int f_idx = 17; + + ml_features[f_idx++] = logf(1.0f + (float)none_rdc->rate); + ml_features[f_idx++] = logf(1.0f + (float)none_rdc->dist); + ml_features[f_idx++] = logf(1.0f + (float)none_rdc->rdcost); + + for (f_idx = 0; f_idx < 20; f_idx++) { + ml_features[f_idx] = (ml_features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx]; + } + + // Get probabilities + float score = 0.0f; + + av1_nn_predict(ml_features, nn_config, &score); + aom_clear_system_state(); + + // Determine if we should prune square partitions. + if (score < thresh) { + *do_square_split = 0; + } +} + +void av1_get_max_min_partition_features(AV1_COMP *const cpi, MACROBLOCK *x, + int mi_row, int mi_col, + float *features) { + AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + + assert(sb_size == BLOCK_128X128); + + int f_idx = 0; + + const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); + aom_clear_system_state(); + const float log_q_sq = logf(1.0f + (float)(dc_q * dc_q) / 256.0f); + + // Perform full-pixel single motion search in Y plane of 16x16 mbs in the sb + float sum_mv_row_sq = 0; + float sum_mv_row = 0; + float min_abs_mv_row = FLT_MAX; + float max_abs_mv_row = 0; + + float sum_mv_col_sq = 0; + float sum_mv_col = 0; + float min_abs_mv_col = FLT_MAX; + float max_abs_mv_col = 0; + + float sum_log_sse_sq = 0; + float sum_log_sse = 0; + float min_log_sse = FLT_MAX; + float max_log_sse = 0; + + const BLOCK_SIZE mb_size = BLOCK_16X16; + const int mb_rows = block_size_high[sb_size] / block_size_high[mb_size]; + const int mb_cols = block_size_wide[sb_size] / block_size_wide[mb_size]; + const int mb_in_mi_size_high_log2 = mi_size_high_log2[mb_size]; + const int mb_in_mi_size_wide_log2 = mi_size_wide_log2[mb_size]; + + for (int mb_row = 0; mb_row < mb_rows; mb_row++) + for (int mb_col = 0; mb_col < mb_cols; mb_col++) { + const int this_mi_row = mi_row + (mb_row << mb_in_mi_size_high_log2); + const int this_mi_col = mi_col + (mb_col << mb_in_mi_size_wide_log2); + unsigned int sse = 0; + unsigned int var = 0; + const MV ref_mv_full = { .row = 0, .col = 0 }; + + av1_simple_motion_sse_var(cpi, x, this_mi_row, this_mi_col, mb_size, + ref_mv_full, 0, &sse, &var); + + aom_clear_system_state(); + const float mv_row = (float)(x->best_mv.as_mv.row / 8); + const float mv_col = (float)(x->best_mv.as_mv.col / 8); + const float log_sse = logf(1.0f + (float)sse); + const float abs_mv_row = fabsf(mv_row); + const float abs_mv_col = fabsf(mv_col); + + sum_mv_row_sq += mv_row * mv_row; + sum_mv_row += mv_row; + sum_mv_col_sq += mv_col * mv_col; + sum_mv_col += mv_col; + + if (abs_mv_row < min_abs_mv_row) min_abs_mv_row = abs_mv_row; + if (abs_mv_row > max_abs_mv_row) max_abs_mv_row = abs_mv_row; + if (abs_mv_col < min_abs_mv_col) min_abs_mv_col = abs_mv_col; + if (abs_mv_col > max_abs_mv_col) max_abs_mv_col = abs_mv_col; + + sum_log_sse_sq += log_sse * log_sse; + sum_log_sse += log_sse; + if (log_sse < min_log_sse) min_log_sse = log_sse; + if (log_sse > max_log_sse) max_log_sse = log_sse; + } + aom_clear_system_state(); + const float avg_mv_row = sum_mv_row / 64.0f; + const float var_mv_row = sum_mv_row_sq / 64.0f - avg_mv_row * avg_mv_row; + + const float avg_mv_col = sum_mv_col / 64.0f; + const float var_mv_col = sum_mv_col_sq / 64.0f - avg_mv_col * avg_mv_col; + + const float avg_log_sse = sum_log_sse / 64.0f; + const float var_log_sse = sum_log_sse_sq / 64.0f - avg_log_sse * avg_log_sse; + + features[f_idx++] = avg_log_sse; + features[f_idx++] = avg_mv_col; + features[f_idx++] = avg_mv_row; + features[f_idx++] = log_q_sq; + features[f_idx++] = max_abs_mv_col; + features[f_idx++] = max_abs_mv_row; + features[f_idx++] = max_log_sse; + features[f_idx++] = min_abs_mv_col; + features[f_idx++] = min_abs_mv_row; + features[f_idx++] = min_log_sse; + features[f_idx++] = var_log_sse; + features[f_idx++] = var_mv_col; + features[f_idx++] = var_mv_row; + + assert(f_idx == FEATURE_SIZE_MAX_MIN_PART_PRED); +} + +BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x, + const float *features) { + float scores[MAX_NUM_CLASSES_MAX_MIN_PART_PRED] = { 0.0f }, + probs[MAX_NUM_CLASSES_MAX_MIN_PART_PRED] = { 0.0f }; + const NN_CONFIG *nn_config = &av1_max_part_pred_nn_config; + + assert(cpi->sf.auto_max_partition_based_on_simple_motion != NOT_IN_USE); + + aom_clear_system_state(); + av1_nn_predict(features, nn_config, scores); + av1_nn_softmax(scores, probs, MAX_NUM_CLASSES_MAX_MIN_PART_PRED); + + int result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; + if (cpi->sf.auto_max_partition_based_on_simple_motion == DIRECT_PRED) { + result = 0; + float max_prob = probs[0]; + for (int i = 1; i < MAX_NUM_CLASSES_MAX_MIN_PART_PRED; ++i) { + if (probs[i] > max_prob) { + max_prob = probs[i]; + result = i; + } + } + } else if (cpi->sf.auto_max_partition_based_on_simple_motion == + RELAXED_PRED) { + for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0; + --result) { + if (result < MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1) { + probs[result] += probs[result + 1]; + } + if (probs[result] > 0.2) break; + } + } else if (cpi->sf.auto_max_partition_based_on_simple_motion == ADAPT_PRED) { + const BLOCK_SIZE sb_size = cpi->common.seq_params.sb_size; + MACROBLOCKD *const xd = &x->e_mbd; + // TODO(debargha): x->source_variance is unavailable at this point, + // so compute. The redundant recomputation later can be removed. + const unsigned int source_variance = + is_cur_buf_hbd(xd) + ? av1_high_get_sby_perpixel_variance(cpi, &x->plane[0].src, sb_size, + xd->bd) + : av1_get_sby_perpixel_variance(cpi, &x->plane[0].src, sb_size); + if (source_variance > 16) { + const double thresh = source_variance < 128 ? 0.05 : 0.1; + for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0; + --result) { + if (result < MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1) { + probs[result] += probs[result + 1]; + } + if (probs[result] > thresh) break; + } + } + } + + return (BLOCK_SIZE)((result + 2) * 3); +} diff --git a/third_party/aom/av1/encoder/partition_strategy.h b/third_party/aom/av1/encoder/partition_strategy.h new file mode 100644 index 0000000000..36b1e95c6b --- /dev/null +++ b/third_party/aom/av1/encoder/partition_strategy.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2019, 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. + */ + +#ifndef AOM_AV1_ENCODER_PARTITION_STRATEGY_H_ +#define AOM_AV1_ENCODER_PARTITION_STRATEGY_H_ + +#include "av1/encoder/encodeframe.h" +#include "av1/encoder/encodemb.h" +#include "av1/encoder/encoder.h" + +#define FEATURE_SIZE_SMS_PRUNE_PART 25 +#define FEATURE_SIZE_SMS_TERM_NONE 28 +#define FEATURE_SIZE_FP_SMS_TERM_NONE 20 +#define FEATURE_SIZE_MAX_MIN_PART_PRED 13 +#define MAX_NUM_CLASSES_MAX_MIN_PART_PRED 4 + +// Performs a simple_motion_search with a single reference frame and extract +// the variance of residues. Then use the features to determine whether we want +// to go straight to splitting without trying PARTITION_NONE +void av1_simple_motion_search_based_split( + AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, int mi_col, + BLOCK_SIZE bsize, int *partition_none_allowed, int *partition_horz_allowed, + int *partition_vert_allowed, int *do_rectangular_split, + int *do_square_split); + +// Performs a simple_motion_search with two reference frames and extract +// the variance of residues. Then use the features to determine whether we want +// to prune some partitions. +void av1_simple_motion_search_prune_part( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, int *partition_none_allowed, + int *partition_horz_allowed, int *partition_vert_allowed, + int *do_square_split, int *do_rectangular_split, int *prune_horz, + int *prune_vert, float *features, int *valid); + +// Early terminates PARTITION_NONE using simple_motion_search features and the +// rate, distortion, and rdcost of PARTITION_NONE. This is only called when: +// - The frame is a show frame +// - The frame is not intra only +// - The current bsize is > BLOCK_8X8 +// - blk_row + blk_height/2 < total_rows and blk_col + blk_width/2 < total_cols +void av1_simple_motion_search_early_term_none( + AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, const RD_STATS *none_rdc, + int *early_terminate, float *simple_motion_features, + int *simple_motion_features_are_valid); + +// Early terminates after PARTITION_NONE in firstpass of two pass partition +// search. +void av1_firstpass_simple_motion_search_early_term(AV1_COMP *const cpi, + MACROBLOCK *x, + PC_TREE *pc_tree, int mi_row, + int mi_col, BLOCK_SIZE bsize, + const RD_STATS *none_rdc, + int *do_square_split); + +// Get the features for selecting the max and min partition size. Currently this +// performs simple_motion_search on 16X16 subblocks of the currnet superblock, +// and then extract the statistics of sse and motion vectors as features. +void av1_get_max_min_partition_features(AV1_COMP *const cpi, MACROBLOCK *x, + int mi_row, int mi_col, + float *features); + +// Predict the maximum BLOCK_SIZE to be used to encoder the current superblock. +BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x, + const float *features); + +// A simplified version of set_offsets meant to be used for +// simple_motion_search. +static INLINE void set_offsets_for_motion_search(const AV1_COMP *const cpi, + MACROBLOCK *const x, + int mi_row, int mi_col, + BLOCK_SIZE bsize) { + const AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + MACROBLOCKD *const xd = &x->e_mbd; + const int mi_width = mi_size_wide[bsize]; + const int mi_height = mi_size_high[bsize]; + + set_mode_info_offsets(cpi, x, xd, mi_row, mi_col); + + // Set up destination pointers. + av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row, mi_col, 0, + num_planes); + + // Set up limit values for MV components. + // Mv beyond the range do not produce new/different prediction block. + x->mv_limits.row_min = + -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND); + x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND); + x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND; + x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND; + + set_plane_n4(xd, mi_width, mi_height, num_planes); + + // Set up distance of MB to edge of frame in 1/8th pel units. + assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1))); + xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8); + xd->mb_to_bottom_edge = ((cm->mi_rows - mi_height - mi_row) * MI_SIZE) * 8; + xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8); + xd->mb_to_right_edge = ((cm->mi_cols - mi_width - mi_col) * MI_SIZE) * 8; + + // Set up source buffers. + av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, bsize); + + // R/D setup. + x->rdmult = cpi->rd.RDMULT; +} + +static INLINE void init_simple_motion_search_mvs(PC_TREE *pc_tree) { + for (int idx = 0; idx < REF_FRAMES; idx++) { + pc_tree->mv_ref_fulls[idx].row = 0; + pc_tree->mv_ref_fulls[idx].col = 0; + } + if (pc_tree->block_size >= BLOCK_8X8) { + init_simple_motion_search_mvs(pc_tree->split[0]); + init_simple_motion_search_mvs(pc_tree->split[1]); + init_simple_motion_search_mvs(pc_tree->split[2]); + init_simple_motion_search_mvs(pc_tree->split[3]); + } +} + +static INLINE int is_full_sb(AV1_COMMON *const cm, int mi_row, int mi_col, + BLOCK_SIZE sb_size) { + const int sb_mi_wide = mi_size_wide[sb_size]; + const int sb_mi_high = mi_size_high[sb_size]; + + return (mi_row + sb_mi_high) <= cm->mi_rows && + (mi_col + sb_mi_wide) <= cm->mi_cols; +} + +static INLINE int use_auto_max_partition(AV1_COMP *const cpi, + BLOCK_SIZE sb_size, int mi_row, + int mi_col) { + AV1_COMMON *const cm = &cpi->common; + + return !frame_is_intra_only(cm) && + cpi->sf.auto_max_partition_based_on_simple_motion != NOT_IN_USE && + sb_size == BLOCK_128X128 && is_full_sb(cm, mi_row, mi_col, sb_size) && + cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index] != + OVERLAY_UPDATE && + cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index] != + INTNL_OVERLAY_UPDATE; +} + +#endif // AOM_AV1_ENCODER_PARTITION_STRATEGY_H_ diff --git a/third_party/aom/av1/encoder/pass2_strategy.c b/third_party/aom/av1/encoder/pass2_strategy.c new file mode 100644 index 0000000000..ac22b68e5f --- /dev/null +++ b/third_party/aom/av1/encoder/pass2_strategy.c @@ -0,0 +1,1787 @@ +/* + * Copyright (c) 2019, 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 + +#include "config/aom_config.h" +#include "config/aom_scale_rtcd.h" + +#include "aom/aom_codec.h" +#include "aom/aom_encoder.h" + +#include "aom_ports/system_state.h" + +#include "av1/common/onyxc_int.h" + +#include "av1/encoder/encoder.h" +#include "av1/encoder/firstpass.h" +#include "av1/encoder/gop_structure.h" + +// Calculate an active area of the image that discounts formatting +// bars and partially discounts other 0 energy areas. +#define MIN_ACTIVE_AREA 0.5 +#define MAX_ACTIVE_AREA 1.0 +double calculate_active_area(const AV1_COMP *cpi, + const FIRSTPASS_STATS *this_frame) { + double active_pct; + + active_pct = + 1.0 - + ((this_frame->intra_skip_pct / 2) + + ((this_frame->inactive_zone_rows * 2) / (double)cpi->common.mb_rows)); + return fclamp(active_pct, MIN_ACTIVE_AREA, MAX_ACTIVE_AREA); +} + +// Calculate a modified Error used in distributing bits between easier and +// harder frames. +#define ACT_AREA_CORRECTION 0.5 +double calculate_modified_err(const AV1_COMP *cpi, const TWO_PASS *twopass, + const AV1EncoderConfig *oxcf, + const FIRSTPASS_STATS *this_frame) { + const FIRSTPASS_STATS *const stats = &twopass->total_stats; + const double av_weight = stats->weight / stats->count; + const double av_err = (stats->coded_error * av_weight) / stats->count; + double modified_error = + av_err * pow(this_frame->coded_error * this_frame->weight / + DOUBLE_DIVIDE_CHECK(av_err), + oxcf->two_pass_vbrbias / 100.0); + + // Correction for active area. Frames with a reduced active area + // (eg due to formatting bars) have a higher error per mb for the + // remaining active MBs. The correction here assumes that coding + // 0.5N blocks of complexity 2X is a little easier than coding N + // blocks of complexity X. + modified_error *= + pow(calculate_active_area(cpi, this_frame), ACT_AREA_CORRECTION); + + return fclamp(modified_error, twopass->modified_error_min, + twopass->modified_error_max); +} + +// Resets the first pass file to the given position using a relative seek from +// the current position. +static void reset_fpf_position(TWO_PASS *p, const FIRSTPASS_STATS *position) { + p->stats_in = position; +} + +static int input_stats(TWO_PASS *p, FIRSTPASS_STATS *fps) { + if (p->stats_in >= p->stats_in_end) return EOF; + + *fps = *p->stats_in; + ++p->stats_in; + return 1; +} + +// Read frame stats at an offset from the current position. +static const FIRSTPASS_STATS *read_frame_stats(const TWO_PASS *p, int offset) { + if ((offset >= 0 && p->stats_in + offset >= p->stats_in_end) || + (offset < 0 && p->stats_in + offset < p->stats_in_start)) { + return NULL; + } + + return &p->stats_in[offset]; +} + +static void subtract_stats(FIRSTPASS_STATS *section, + const FIRSTPASS_STATS *frame) { + section->frame -= frame->frame; + section->weight -= frame->weight; + section->intra_error -= frame->intra_error; + section->frame_avg_wavelet_energy -= frame->frame_avg_wavelet_energy; + section->coded_error -= frame->coded_error; + section->sr_coded_error -= frame->sr_coded_error; + section->pcnt_inter -= frame->pcnt_inter; + section->pcnt_motion -= frame->pcnt_motion; + section->pcnt_second_ref -= frame->pcnt_second_ref; + section->pcnt_neutral -= frame->pcnt_neutral; + section->intra_skip_pct -= frame->intra_skip_pct; + section->inactive_zone_rows -= frame->inactive_zone_rows; + section->inactive_zone_cols -= frame->inactive_zone_cols; + section->MVr -= frame->MVr; + section->mvr_abs -= frame->mvr_abs; + section->MVc -= frame->MVc; + section->mvc_abs -= frame->mvc_abs; + section->MVrv -= frame->MVrv; + section->MVcv -= frame->MVcv; + section->mv_in_out_count -= frame->mv_in_out_count; + section->new_mv_count -= frame->new_mv_count; + section->count -= frame->count; + section->duration -= frame->duration; +} + +// Calculate the linear size relative to a baseline of 1080P +#define BASE_SIZE 2073600.0 // 1920x1080 +static double get_linear_size_factor(const AV1_COMP *cpi) { + const double this_area = cpi->initial_width * cpi->initial_height; + return pow(this_area / BASE_SIZE, 0.5); +} + +// This function returns the maximum target rate per frame. +static int frame_max_bits(const RATE_CONTROL *rc, + const AV1EncoderConfig *oxcf) { + int64_t max_bits = ((int64_t)rc->avg_frame_bandwidth * + (int64_t)oxcf->two_pass_vbrmax_section) / + 100; + if (max_bits < 0) + max_bits = 0; + else if (max_bits > rc->max_frame_bandwidth) + max_bits = rc->max_frame_bandwidth; + + return (int)max_bits; +} + +static double calc_correction_factor(double err_per_mb, double err_divisor, + double pt_low, double pt_high, int q, + aom_bit_depth_t bit_depth) { + const double error_term = err_per_mb / err_divisor; + + // Adjustment based on actual quantizer to power term. + const double power_term = + AOMMIN(av1_convert_qindex_to_q(q, bit_depth) * 0.01 + pt_low, pt_high); + + // Calculate correction factor. + if (power_term < 1.0) assert(error_term >= 0.0); + + return fclamp(pow(error_term, power_term), 0.05, 5.0); +} + +#define ERR_DIVISOR 100.0 +#define FACTOR_PT_LOW 0.70 +#define FACTOR_PT_HIGH 0.90 + +// Similar to find_qindex_by_rate() function in ratectrl.c, but includes +// calculation of a correction_factor. +static int find_qindex_by_rate_with_correction( + int desired_bits_per_mb, aom_bit_depth_t bit_depth, FRAME_TYPE frame_type, + double error_per_mb, double ediv_size_correction, + double group_weight_factor, int best_qindex, int worst_qindex) { + assert(best_qindex <= worst_qindex); + int low = best_qindex; + int high = worst_qindex; + while (low < high) { + const int mid = (low + high) >> 1; + const double mid_factor = + calc_correction_factor(error_per_mb, ERR_DIVISOR - ediv_size_correction, + FACTOR_PT_LOW, FACTOR_PT_HIGH, mid, bit_depth); + const int mid_bits_per_mb = av1_rc_bits_per_mb( + frame_type, mid, mid_factor * group_weight_factor, bit_depth); + if (mid_bits_per_mb > desired_bits_per_mb) { + low = mid + 1; + } else { + high = mid; + } + } +#if CONFIG_DEBUG + assert(low == high); + const double low_factor = + calc_correction_factor(error_per_mb, ERR_DIVISOR - ediv_size_correction, + FACTOR_PT_LOW, FACTOR_PT_HIGH, low, bit_depth); + const int low_bits_per_mb = av1_rc_bits_per_mb( + frame_type, low, low_factor * group_weight_factor, bit_depth); + assert(low_bits_per_mb <= desired_bits_per_mb || low == worst_qindex); +#endif // CONFIG_DEBUG + return low; +} + +static int get_twopass_worst_quality(const AV1_COMP *cpi, + const double section_err, + double inactive_zone, + int section_target_bandwidth, + double group_weight_factor) { + const RATE_CONTROL *const rc = &cpi->rc; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + + inactive_zone = fclamp(inactive_zone, 0.0, 1.0); + + if (section_target_bandwidth <= 0) { + return rc->worst_quality; // Highest value allowed + } else { + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) + ? cpi->initial_mbs + : cpi->common.MBs; + const int active_mbs = AOMMAX(1, num_mbs - (int)(num_mbs * inactive_zone)); + const double av_err_per_mb = section_err / active_mbs; + const int target_norm_bits_per_mb = + (int)((uint64_t)section_target_bandwidth << BPER_MB_NORMBITS) / + active_mbs; + + // Larger image formats are expected to be a little harder to code + // relatively given the same prediction error score. This in part at + // least relates to the increased size and hence coding overheads of + // motion vectors. Some account of this is made through adjustment of + // the error divisor. + double ediv_size_correction = + AOMMAX(0.2, AOMMIN(5.0, get_linear_size_factor(cpi))); + if (ediv_size_correction < 1.0) + ediv_size_correction = -(1.0 / ediv_size_correction); + ediv_size_correction *= 4.0; + + // Try and pick a max Q that will be high enough to encode the + // content at the given rate. + int q = find_qindex_by_rate_with_correction( + target_norm_bits_per_mb, cpi->common.seq_params.bit_depth, INTER_FRAME, + av_err_per_mb, ediv_size_correction, group_weight_factor, + rc->best_quality, rc->worst_quality); + + // Restriction on active max q for constrained quality mode. + if (cpi->oxcf.rc_mode == AOM_CQ) q = AOMMAX(q, oxcf->cq_level); + return q; + } +} + +#define SR_DIFF_PART 0.0015 +#define MOTION_AMP_PART 0.003 +#define INTRA_PART 0.005 +#define DEFAULT_DECAY_LIMIT 0.75 +#define LOW_SR_DIFF_TRHESH 0.1 +#define SR_DIFF_MAX 128.0 +#define NCOUNT_FRAME_II_THRESH 5.0 + +static double get_sr_decay_rate(const AV1_COMP *cpi, + const FIRSTPASS_STATS *frame) { + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs + : cpi->common.MBs; + double sr_diff = (frame->sr_coded_error - frame->coded_error) / num_mbs; + double sr_decay = 1.0; + double modified_pct_inter; + double modified_pcnt_intra; + const double motion_amplitude_factor = + frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) / 2); + + modified_pct_inter = frame->pcnt_inter; + if ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) < + (double)NCOUNT_FRAME_II_THRESH) { + modified_pct_inter = frame->pcnt_inter - frame->pcnt_neutral; + } + modified_pcnt_intra = 100 * (1.0 - modified_pct_inter); + + if ((sr_diff > LOW_SR_DIFF_TRHESH)) { + sr_diff = AOMMIN(sr_diff, SR_DIFF_MAX); + sr_decay = 1.0 - (SR_DIFF_PART * sr_diff) - + (MOTION_AMP_PART * motion_amplitude_factor) - + (INTRA_PART * modified_pcnt_intra); + } + return AOMMAX(sr_decay, AOMMIN(DEFAULT_DECAY_LIMIT, modified_pct_inter)); +} + +// This function gives an estimate of how badly we believe the prediction +// quality is decaying from frame to frame. +static double get_zero_motion_factor(const AV1_COMP *cpi, + const FIRSTPASS_STATS *frame) { + const double zero_motion_pct = frame->pcnt_inter - frame->pcnt_motion; + double sr_decay = get_sr_decay_rate(cpi, frame); + return AOMMIN(sr_decay, zero_motion_pct); +} + +#define ZM_POWER_FACTOR 0.75 + +static double get_prediction_decay_rate(const AV1_COMP *cpi, + const FIRSTPASS_STATS *next_frame) { + const double sr_decay_rate = get_sr_decay_rate(cpi, next_frame); + const double zero_motion_factor = + (0.95 * pow((next_frame->pcnt_inter - next_frame->pcnt_motion), + ZM_POWER_FACTOR)); + + return AOMMAX(zero_motion_factor, + (sr_decay_rate + ((1.0 - sr_decay_rate) * zero_motion_factor))); +} + +// Function to test for a condition where a complex transition is followed +// by a static section. For example in slide shows where there is a fade +// between slides. This is to help with more optimal kf and gf positioning. +static int detect_transition_to_still(AV1_COMP *cpi, int frame_interval, + int still_interval, + double loop_decay_rate, + double last_decay_rate) { + TWO_PASS *const twopass = &cpi->twopass; + RATE_CONTROL *const rc = &cpi->rc; + + // Break clause to detect very still sections after motion + // For example a static image after a fade or other transition + // instead of a clean scene cut. + if (frame_interval > rc->min_gf_interval && loop_decay_rate >= 0.999 && + last_decay_rate < 0.9) { + int j; + + // Look ahead a few frames to see if static condition persists... + for (j = 0; j < still_interval; ++j) { + const FIRSTPASS_STATS *stats = &twopass->stats_in[j]; + if (stats >= twopass->stats_in_end) break; + + if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break; + } + + // Only if it does do we signal a transition to still. + return j == still_interval; + } + + return 0; +} + +// This function detects a flash through the high relative pcnt_second_ref +// score in the frame following a flash frame. The offset passed in should +// reflect this. +static int detect_flash(const TWO_PASS *twopass, int offset) { + const FIRSTPASS_STATS *const next_frame = read_frame_stats(twopass, offset); + + // What we are looking for here is a situation where there is a + // brief break in prediction (such as a flash) but subsequent frames + // are reasonably well predicted by an earlier (pre flash) frame. + // The recovery after a flash is indicated by a high pcnt_second_ref + // compared to pcnt_inter. + return next_frame != NULL && + next_frame->pcnt_second_ref > next_frame->pcnt_inter && + next_frame->pcnt_second_ref >= 0.5; +} + +// Update the motion related elements to the GF arf boost calculation. +static void accumulate_frame_motion_stats(const FIRSTPASS_STATS *stats, + double *mv_in_out, + double *mv_in_out_accumulator, + double *abs_mv_in_out_accumulator, + double *mv_ratio_accumulator) { + const double pct = stats->pcnt_motion; + + // Accumulate Motion In/Out of frame stats. + *mv_in_out = stats->mv_in_out_count * pct; + *mv_in_out_accumulator += *mv_in_out; + *abs_mv_in_out_accumulator += fabs(*mv_in_out); + + // Accumulate a measure of how uniform (or conversely how random) the motion + // field is (a ratio of abs(mv) / mv). + if (pct > 0.05) { + const double mvr_ratio = + fabs(stats->mvr_abs) / DOUBLE_DIVIDE_CHECK(fabs(stats->MVr)); + const double mvc_ratio = + fabs(stats->mvc_abs) / DOUBLE_DIVIDE_CHECK(fabs(stats->MVc)); + + *mv_ratio_accumulator += + pct * (mvr_ratio < stats->mvr_abs ? mvr_ratio : stats->mvr_abs); + *mv_ratio_accumulator += + pct * (mvc_ratio < stats->mvc_abs ? mvc_ratio : stats->mvc_abs); + } +} + +#define BASELINE_ERR_PER_MB 1000.0 +#define BOOST_FACTOR 12.5 + +static double calc_frame_boost(AV1_COMP *cpi, const FIRSTPASS_STATS *this_frame, + double this_frame_mv_in_out, double max_boost) { + double frame_boost; + const double lq = av1_convert_qindex_to_q( + cpi->rc.avg_frame_qindex[INTER_FRAME], cpi->common.seq_params.bit_depth); + const double boost_q_correction = AOMMIN((0.5 + (lq * 0.015)), 1.5); + int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs + : cpi->common.MBs; + + // Correct for any inactive region in the image + num_mbs = (int)AOMMAX(1, num_mbs * calculate_active_area(cpi, this_frame)); + + // Underlying boost factor is based on inter error ratio. + frame_boost = (BASELINE_ERR_PER_MB * num_mbs) / + DOUBLE_DIVIDE_CHECK(this_frame->coded_error); + frame_boost = frame_boost * BOOST_FACTOR * boost_q_correction; + + // Increase boost for frames where new data coming into frame (e.g. zoom out). + // Slightly reduce boost if there is a net balance of motion out of the frame + // (zoom in). The range for this_frame_mv_in_out is -1.0 to +1.0. + if (this_frame_mv_in_out > 0.0) + frame_boost += frame_boost * (this_frame_mv_in_out * 2.0); + // In the extreme case the boost is halved. + else + frame_boost += frame_boost * (this_frame_mv_in_out / 2.0); + + return AOMMIN(frame_boost, max_boost * boost_q_correction); +} + +#define GF_MAX_BOOST 90.0 +#define MIN_ARF_GF_BOOST 240 +#define MIN_DECAY_FACTOR 0.01 + +static int calc_arf_boost(AV1_COMP *cpi, int offset, int f_frames, int b_frames, + int *f_boost, int *b_boost) { + TWO_PASS *const twopass = &cpi->twopass; + int i; + double boost_score = 0.0; + double mv_ratio_accumulator = 0.0; + double decay_accumulator = 1.0; + double this_frame_mv_in_out = 0.0; + double mv_in_out_accumulator = 0.0; + double abs_mv_in_out_accumulator = 0.0; + int arf_boost; + int flash_detected = 0; + + // Search forward from the proposed arf/next gf position. + for (i = 0; i < f_frames; ++i) { + const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset); + if (this_frame == NULL) break; + + // Update the motion related elements to the boost calculation. + accumulate_frame_motion_stats( + this_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, + &abs_mv_in_out_accumulator, &mv_ratio_accumulator); + + // We want to discount the flash frame itself and the recovery + // frame that follows as both will have poor scores. + flash_detected = detect_flash(twopass, i + offset) || + detect_flash(twopass, i + offset + 1); + + // Accumulate the effect of prediction quality decay. + if (!flash_detected) { + decay_accumulator *= get_prediction_decay_rate(cpi, this_frame); + decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR + ? MIN_DECAY_FACTOR + : decay_accumulator; + } + + boost_score += + decay_accumulator * + calc_frame_boost(cpi, this_frame, this_frame_mv_in_out, GF_MAX_BOOST); + } + + *f_boost = (int)boost_score; + + // Reset for backward looking loop. + boost_score = 0.0; + mv_ratio_accumulator = 0.0; + decay_accumulator = 1.0; + this_frame_mv_in_out = 0.0; + mv_in_out_accumulator = 0.0; + abs_mv_in_out_accumulator = 0.0; + + // Search backward towards last gf position. + for (i = -1; i >= -b_frames; --i) { + const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset); + if (this_frame == NULL) break; + + // Update the motion related elements to the boost calculation. + accumulate_frame_motion_stats( + this_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, + &abs_mv_in_out_accumulator, &mv_ratio_accumulator); + + // We want to discount the the flash frame itself and the recovery + // frame that follows as both will have poor scores. + flash_detected = detect_flash(twopass, i + offset) || + detect_flash(twopass, i + offset + 1); + + // Cumulative effect of prediction quality decay. + if (!flash_detected) { + decay_accumulator *= get_prediction_decay_rate(cpi, this_frame); + decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR + ? MIN_DECAY_FACTOR + : decay_accumulator; + } + + boost_score += + decay_accumulator * + calc_frame_boost(cpi, this_frame, this_frame_mv_in_out, GF_MAX_BOOST); + } + *b_boost = (int)boost_score; + + arf_boost = (*f_boost + *b_boost); + if (arf_boost < ((b_frames + f_frames) * 20)) + arf_boost = ((b_frames + f_frames) * 20); + arf_boost = AOMMAX(arf_boost, MIN_ARF_GF_BOOST); + + return arf_boost; +} + +// Calculate a section intra ratio used in setting max loop filter. +static int calculate_section_intra_ratio(const FIRSTPASS_STATS *begin, + const FIRSTPASS_STATS *end, + int section_length) { + const FIRSTPASS_STATS *s = begin; + double intra_error = 0.0; + double coded_error = 0.0; + int i = 0; + + while (s < end && i < section_length) { + intra_error += s->intra_error; + coded_error += s->coded_error; + ++s; + ++i; + } + + return (int)(intra_error / DOUBLE_DIVIDE_CHECK(coded_error)); +} + +// Calculate the total bits to allocate in this GF/ARF group. +static int64_t calculate_total_gf_group_bits(AV1_COMP *cpi, + double gf_group_err) { + const RATE_CONTROL *const rc = &cpi->rc; + const TWO_PASS *const twopass = &cpi->twopass; + const int max_bits = frame_max_bits(rc, &cpi->oxcf); + int64_t total_group_bits; + + // Calculate the bits to be allocated to the group as a whole. + if ((twopass->kf_group_bits > 0) && (twopass->kf_group_error_left > 0)) { + total_group_bits = (int64_t)(twopass->kf_group_bits * + (gf_group_err / twopass->kf_group_error_left)); + } else { + total_group_bits = 0; + } + + // Clamp odd edge cases. + total_group_bits = (total_group_bits < 0) + ? 0 + : (total_group_bits > twopass->kf_group_bits) + ? twopass->kf_group_bits + : total_group_bits; + + // Clip based on user supplied data rate variability limit. + if (total_group_bits > (int64_t)max_bits * rc->baseline_gf_interval) + total_group_bits = (int64_t)max_bits * rc->baseline_gf_interval; + + return total_group_bits; +} + +// Calculate the number bits extra to assign to boosted frames in a group. +static int calculate_boost_bits(int frame_count, int boost, + int64_t total_group_bits) { + int allocation_chunks; + + // return 0 for invalid inputs (could arise e.g. through rounding errors) + if (!boost || (total_group_bits <= 0) || (frame_count <= 0)) return 0; + + allocation_chunks = (frame_count * 100) + boost; + + // Prevent overflow. + if (boost > 1023) { + int divisor = boost >> 10; + boost /= divisor; + allocation_chunks /= divisor; + } + + // Calculate the number of extra bits for use in the boosted frame or frames. + return AOMMAX((int)(((int64_t)boost * total_group_bits) / allocation_chunks), + 0); +} + +#define LEAF_REDUCTION_FACTOR 0.75 +static double lvl_budget_factor[MAX_PYRAMID_LVL - 1][MAX_PYRAMID_LVL - 1] = { + { 1.0, 0.0, 0.0 }, { 0.6, 0.4, 0 }, { 0.45, 0.35, 0.20 } +}; +static void allocate_gf_group_bits( + AV1_COMP *cpi, int64_t gf_group_bits, double group_error, int gf_arf_bits, + const EncodeFrameParams *const frame_params) { + RATE_CONTROL *const rc = &cpi->rc; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + TWO_PASS *const twopass = &cpi->twopass; + GF_GROUP *const gf_group = &twopass->gf_group; + const int key_frame = (frame_params->frame_type == KEY_FRAME); + const int max_bits = frame_max_bits(&cpi->rc, &cpi->oxcf); + int64_t total_group_bits = gf_group_bits; + + // Check if GF group has any internal arfs. + int has_internal_arfs = 0; + for (int i = 0; i < gf_group->size; ++i) { + if (gf_group->update_type[i] == INTNL_ARF_UPDATE) { + has_internal_arfs = 1; + break; + } + } + + // For key frames the frame target rate is already set and it + // is also the golden frame. + // === [frame_index == 0] === + int frame_index = 0; + if (!key_frame) { + if (rc->source_alt_ref_active) + gf_group->bit_allocation[frame_index] = 0; + else + gf_group->bit_allocation[frame_index] = gf_arf_bits; + + // Step over the golden frame / overlay frame + FIRSTPASS_STATS frame_stats; + if (EOF == input_stats(twopass, &frame_stats)) return; + } + + // Deduct the boost bits for arf (or gf if it is not a key frame) + // from the group total. + if (rc->source_alt_ref_pending || !key_frame) total_group_bits -= gf_arf_bits; + + frame_index++; + + // Store the bits to spend on the ARF if there is one. + // === [frame_index == 1] === + if (rc->source_alt_ref_pending) { + gf_group->bit_allocation[frame_index] = gf_arf_bits; + + ++frame_index; + + // Skip all the internal ARFs right after ARF at the starting segment of + // the current GF group. + if (has_internal_arfs) { + while (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) { + ++frame_index; + } + } + } + + // Save. + const int tmp_frame_index = frame_index; + int budget_reduced_from_leaf_level = 0; + + // Allocate bits to frames other than first frame, which is either a keyframe, + // overlay frame or golden frame. + const int normal_frames = rc->baseline_gf_interval - 1; + + for (int i = 0; i < normal_frames; ++i) { + FIRSTPASS_STATS frame_stats; + if (EOF == input_stats(twopass, &frame_stats)) break; + + const double modified_err = + calculate_modified_err(cpi, twopass, oxcf, &frame_stats); + const double err_fraction = + (group_error > 0) ? modified_err / DOUBLE_DIVIDE_CHECK(group_error) + : 0.0; + const int target_frame_size = + clamp((int)((double)total_group_bits * err_fraction), 0, + AOMMIN(max_bits, (int)total_group_bits)); + + if (gf_group->update_type[frame_index] == INTNL_OVERLAY_UPDATE) { + assert(gf_group->pyramid_height <= MAX_PYRAMID_LVL && + "non-valid height for a pyramid structure"); + + const int arf_pos = gf_group->arf_pos_in_gf[frame_index]; + gf_group->bit_allocation[frame_index] = 0; + + gf_group->bit_allocation[arf_pos] = target_frame_size; + // Note: Boost, if needed, is added in the next loop. + } else { + assert(gf_group->update_type[frame_index] == LF_UPDATE); + gf_group->bit_allocation[frame_index] = target_frame_size; + if (has_internal_arfs) { + const int this_budget_reduction = + (int)(target_frame_size * LEAF_REDUCTION_FACTOR); + gf_group->bit_allocation[frame_index] -= this_budget_reduction; + budget_reduced_from_leaf_level += this_budget_reduction; + } + } + + ++frame_index; + + // Skip all the internal ARFs. + if (has_internal_arfs) { + while (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) + ++frame_index; + } + } + + if (budget_reduced_from_leaf_level > 0) { + assert(has_internal_arfs); + // Restore. + frame_index = tmp_frame_index; + + // Re-distribute this extra budget to overlay frames in the group. + for (int i = 0; i < normal_frames; ++i) { + if (gf_group->update_type[frame_index] == INTNL_OVERLAY_UPDATE) { + assert(gf_group->pyramid_height <= MAX_PYRAMID_LVL && + "non-valid height for a pyramid structure"); + const int arf_pos = gf_group->arf_pos_in_gf[frame_index]; + const int this_lvl = gf_group->pyramid_level[arf_pos]; + const int dist2top = gf_group->pyramid_height - 1 - this_lvl; + const double lvl_boost_factor = + lvl_budget_factor[gf_group->pyramid_height - 2][dist2top]; + const int extra_size = + (int)(budget_reduced_from_leaf_level * lvl_boost_factor / + gf_group->pyramid_lvl_nodes[this_lvl]); + gf_group->bit_allocation[arf_pos] += extra_size; + } + ++frame_index; + + // Skip all the internal ARFs. + if (has_internal_arfs) { + while (gf_group->update_type[frame_index] == INTNL_ARF_UPDATE) { + ++frame_index; + } + } + } + } +} + +// Given the maximum allowed height of the pyramid structure, return the fixed +// GF length to be used. +static INLINE int get_fixed_gf_length(int max_pyr_height) { + (void)max_pyr_height; + return MAX_GF_INTERVAL; +} + +// Returns true if KF group and GF group both are almost completely static. +static INLINE int is_almost_static(double gf_zero_motion, int kf_zero_motion) { + return (gf_zero_motion >= 0.995) && + (kf_zero_motion >= STATIC_KF_GROUP_THRESH); +} + +#define ARF_ABS_ZOOM_THRESH 4.4 +#define GROUP_ADAPTIVE_MAXQ 1 +#if GROUP_ADAPTIVE_MAXQ +#define RC_FACTOR_MIN 0.75 +#define RC_FACTOR_MAX 1.75 +#endif // GROUP_ADAPTIVE_MAXQ +#define MIN_FWD_KF_INTERVAL 8 + +// Analyse and define a gf/arf group. +static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, + const EncodeFrameParams *const frame_params) { + AV1_COMMON *const cm = &cpi->common; + RATE_CONTROL *const rc = &cpi->rc; + AV1EncoderConfig *const oxcf = &cpi->oxcf; + TWO_PASS *const twopass = &cpi->twopass; + FIRSTPASS_STATS next_frame; + const FIRSTPASS_STATS *const start_pos = twopass->stats_in; + int i; + + double boost_score = 0.0; + double gf_group_err = 0.0; +#if GROUP_ADAPTIVE_MAXQ + double gf_group_raw_error = 0.0; +#endif + double gf_group_skip_pct = 0.0; + double gf_group_inactive_zone_rows = 0.0; + double gf_first_frame_err = 0.0; + double mod_frame_err = 0.0; + + double mv_ratio_accumulator = 0.0; + double decay_accumulator = 1.0; + double zero_motion_accumulator = 1.0; + + double loop_decay_rate = 1.00; + double last_loop_decay_rate = 1.00; + + double this_frame_mv_in_out = 0.0; + double mv_in_out_accumulator = 0.0; + double abs_mv_in_out_accumulator = 0.0; + + unsigned int allow_alt_ref = is_altref_enabled(cpi); + + int f_boost = 0; + int b_boost = 0; + int flash_detected; + int64_t gf_group_bits; + double gf_group_error_left; + int gf_arf_bits; + const int is_intra_only = frame_params->frame_type == KEY_FRAME || + frame_params->frame_type == INTRA_ONLY_FRAME; + const int arf_active_or_kf = is_intra_only || rc->source_alt_ref_active; + + cpi->internal_altref_allowed = (oxcf->gf_max_pyr_height > 1); + + // Reset the GF group data structures unless this is a key + // frame in which case it will already have been done. + if (!is_intra_only) { + av1_zero(twopass->gf_group); + } + + aom_clear_system_state(); + av1_zero(next_frame); + + // Load stats for the current frame. + mod_frame_err = calculate_modified_err(cpi, twopass, oxcf, this_frame); + + // Note the error of the frame at the start of the group. This will be + // the GF frame error if we code a normal gf. + gf_first_frame_err = mod_frame_err; + + // If this is a key frame or the overlay from a previous arf then + // the error score / cost of this frame has already been accounted for. + if (arf_active_or_kf) { + gf_group_err -= gf_first_frame_err; +#if GROUP_ADAPTIVE_MAXQ + gf_group_raw_error -= this_frame->coded_error; +#endif + gf_group_skip_pct -= this_frame->intra_skip_pct; + gf_group_inactive_zone_rows -= this_frame->inactive_zone_rows; + } + // Motion breakout threshold for loop below depends on image size. + const double mv_ratio_accumulator_thresh = + (cpi->initial_height + cpi->initial_width) / 4.0; + + // TODO(urvang): Try logic to vary min and max interval based on q. + const int active_min_gf_interval = rc->min_gf_interval; + const int active_max_gf_interval = + AOMMIN(rc->max_gf_interval, get_fixed_gf_length(oxcf->gf_max_pyr_height)); + + double avg_sr_coded_error = 0; + double avg_raw_err_stdev = 0; + int non_zero_stdev_count = 0; + + i = 0; + while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) { + ++i; + + // Accumulate error score of frames in this gf group. + mod_frame_err = calculate_modified_err(cpi, twopass, oxcf, this_frame); + gf_group_err += mod_frame_err; +#if GROUP_ADAPTIVE_MAXQ + gf_group_raw_error += this_frame->coded_error; +#endif + gf_group_skip_pct += this_frame->intra_skip_pct; + gf_group_inactive_zone_rows += this_frame->inactive_zone_rows; + + if (EOF == input_stats(twopass, &next_frame)) break; + + // Test for the case where there is a brief flash but the prediction + // quality back to an earlier frame is then restored. + flash_detected = detect_flash(twopass, 0); + + // Update the motion related elements to the boost calculation. + accumulate_frame_motion_stats( + &next_frame, &this_frame_mv_in_out, &mv_in_out_accumulator, + &abs_mv_in_out_accumulator, &mv_ratio_accumulator); + // sum up the metric values of current gf group + avg_sr_coded_error += next_frame.sr_coded_error; + if (fabs(next_frame.raw_error_stdev) > 0.000001) { + non_zero_stdev_count++; + avg_raw_err_stdev += next_frame.raw_error_stdev; + } + + // Accumulate the effect of prediction quality decay. + if (!flash_detected) { + last_loop_decay_rate = loop_decay_rate; + loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame); + + decay_accumulator = decay_accumulator * loop_decay_rate; + + // Monitor for static sections. + if ((rc->frames_since_key + i - 1) > 1) { + zero_motion_accumulator = AOMMIN( + zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame)); + } + + // Break clause to detect very still sections after motion. For example, + // a static image after a fade or other transition. + if (detect_transition_to_still(cpi, i, 5, loop_decay_rate, + last_loop_decay_rate)) { + allow_alt_ref = 0; + break; + } + } + + // Calculate a boost number for this frame. + boost_score += + decay_accumulator * + calc_frame_boost(cpi, &next_frame, this_frame_mv_in_out, GF_MAX_BOOST); + // If almost totally static, we will not use the the max GF length later, + // so we can continue for more frames. + if ((i >= active_max_gf_interval + 1) && + !is_almost_static(zero_motion_accumulator, + twopass->kf_zeromotion_pct)) { + break; + } + + // Some conditions to breakout after min interval. + if (i >= active_min_gf_interval && + // If possible don't break very close to a kf + (rc->frames_to_key - i >= rc->min_gf_interval) && (i & 0x01) && + !flash_detected && + (mv_ratio_accumulator > mv_ratio_accumulator_thresh || + abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH)) { + break; + } + *this_frame = next_frame; + } + + // Was the group length constrained by the requirement for a new KF? + rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0; + + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs + : cpi->common.MBs; + assert(num_mbs > 0); + if (i) avg_sr_coded_error /= i; + + if (non_zero_stdev_count) avg_raw_err_stdev /= non_zero_stdev_count; + + // Disable internal ARFs for "still" gf groups. + // zero_motion_accumulator: minimum percentage of (0,0) motion; + // avg_sr_coded_error: average of the SSE per pixel of each frame; + // avg_raw_err_stdev: average of the standard deviation of (0,0) + // motion error per block of each frame. + if (zero_motion_accumulator > MIN_ZERO_MOTION && + avg_sr_coded_error / num_mbs < MAX_SR_CODED_ERROR && + avg_raw_err_stdev < MAX_RAW_ERR_VAR) { + cpi->internal_altref_allowed = 0; + } + + const int use_alt_ref = + !is_almost_static(zero_motion_accumulator, twopass->kf_zeromotion_pct) && + allow_alt_ref && (i < cpi->oxcf.lag_in_frames) && + (i >= rc->min_gf_interval) && + (cpi->oxcf.gf_max_pyr_height > MIN_PYRAMID_LVL); + +#define REDUCE_GF_LENGTH_THRESH 4 +#define REDUCE_GF_LENGTH_TO_KEY_THRESH 9 +#define REDUCE_GF_LENGTH_BY 1 + int alt_offset = 0; + // The length reduction strategy is tweaked for certain cases, and doesn't + // work well for certain other cases. + const int allow_gf_length_reduction = + ((cpi->oxcf.rc_mode == AOM_Q && cpi->oxcf.cq_level <= 128) || + !cpi->internal_altref_allowed) && + !is_lossless_requested(&cpi->oxcf); + + if (allow_gf_length_reduction && use_alt_ref) { + // adjust length of this gf group if one of the following condition met + // 1: only one overlay frame left and this gf is too long + // 2: next gf group is too short to have arf compared to the current gf + + // maximum length of next gf group + const int next_gf_len = rc->frames_to_key - i; + const int single_overlay_left = + next_gf_len == 0 && i > REDUCE_GF_LENGTH_THRESH; + // the next gf is probably going to have a ARF but it will be shorter than + // this gf + const int unbalanced_gf = + i > REDUCE_GF_LENGTH_TO_KEY_THRESH && + next_gf_len + 1 < REDUCE_GF_LENGTH_TO_KEY_THRESH && + next_gf_len + 1 >= rc->min_gf_interval; + + if (single_overlay_left || unbalanced_gf) { + const int roll_back = REDUCE_GF_LENGTH_BY; + // Reduce length only if active_min_gf_interval will be respected later. + if (i - roll_back >= active_min_gf_interval + 1) { + alt_offset = -roll_back; + i -= roll_back; + } + } + } + + // Should we use the alternate reference frame. + if (use_alt_ref) { + // Calculate the boost for alt ref. + rc->gfu_boost = + calc_arf_boost(cpi, alt_offset, (i - 1), (i - 1), &f_boost, &b_boost); + rc->source_alt_ref_pending = 1; + + // do not replace ARFs with overlay frames, and keep it as GOLDEN_REF + cpi->preserve_arf_as_gld = 1; + } else { + rc->gfu_boost = AOMMAX((int)boost_score, MIN_ARF_GF_BOOST); + rc->source_alt_ref_pending = 0; + cpi->preserve_arf_as_gld = 0; + } + + // Set the interval until the next gf. + // If forward keyframes are enabled, ensure the final gf group obeys the + // MIN_FWD_KF_INTERVAL. + if (cpi->oxcf.fwd_kf_enabled && + ((twopass->stats_in - i + rc->frames_to_key) < twopass->stats_in_end)) { + if (i == rc->frames_to_key) { + rc->baseline_gf_interval = i; + // if the last gf group will be smaller than MIN_FWD_KF_INTERVAL + } else if ((rc->frames_to_key - i < + AOMMAX(MIN_FWD_KF_INTERVAL, rc->min_gf_interval)) && + (rc->frames_to_key != i)) { + // if possible, merge the last two gf groups + if (rc->frames_to_key <= active_max_gf_interval) { + rc->baseline_gf_interval = rc->frames_to_key; + // if merging the last two gf groups creates a group that is too long, + // split them and force the last gf group to be the MIN_FWD_KF_INTERVAL + } else { + rc->baseline_gf_interval = rc->frames_to_key - MIN_FWD_KF_INTERVAL; + } + } else { + rc->baseline_gf_interval = i - rc->source_alt_ref_pending; + } + } else { + rc->baseline_gf_interval = i - rc->source_alt_ref_pending; + } + +#define LAST_ALR_BOOST_FACTOR 0.2f + rc->arf_boost_factor = 1.0; + if (rc->source_alt_ref_pending && !is_lossless_requested(&cpi->oxcf)) { + // Reduce the boost of altref in the last gf group + if (rc->frames_to_key - i == REDUCE_GF_LENGTH_BY || + rc->frames_to_key - i == 0) { + rc->arf_boost_factor = LAST_ALR_BOOST_FACTOR; + } + } + + rc->frames_till_gf_update_due = rc->baseline_gf_interval; + + // Reset the file position. + reset_fpf_position(twopass, start_pos); + + // Calculate the bits to be allocated to the gf/arf group as a whole + gf_group_bits = calculate_total_gf_group_bits(cpi, gf_group_err); + +#if GROUP_ADAPTIVE_MAXQ + // Calculate an estimate of the maxq needed for the group. + // We are more agressive about correcting for sections + // where there could be significant overshoot than for easier + // sections where we do not wish to risk creating an overshoot + // of the allocated bit budget. + if ((cpi->oxcf.rc_mode != AOM_Q) && (rc->baseline_gf_interval > 1)) { + const int vbr_group_bits_per_frame = + (int)(gf_group_bits / rc->baseline_gf_interval); + const double group_av_err = gf_group_raw_error / rc->baseline_gf_interval; + const double group_av_skip_pct = + gf_group_skip_pct / rc->baseline_gf_interval; + const double group_av_inactive_zone = + ((gf_group_inactive_zone_rows * 2) / + (rc->baseline_gf_interval * (double)cm->mb_rows)); + + int tmp_q; + // rc factor is a weight factor that corrects for local rate control drift. + double rc_factor = 1.0; + if (rc->rate_error_estimate > 0) { + rc_factor = AOMMAX(RC_FACTOR_MIN, + (double)(100 - rc->rate_error_estimate) / 100.0); + } else { + rc_factor = AOMMIN(RC_FACTOR_MAX, + (double)(100 - rc->rate_error_estimate) / 100.0); + } + tmp_q = get_twopass_worst_quality( + cpi, group_av_err, (group_av_skip_pct + group_av_inactive_zone), + vbr_group_bits_per_frame, twopass->kfgroup_inter_fraction * rc_factor); + twopass->active_worst_quality = + AOMMAX(tmp_q, twopass->active_worst_quality >> 1); + } +#endif + + // Calculate the extra bits to be used for boosted frame(s) + gf_arf_bits = calculate_boost_bits(rc->baseline_gf_interval, rc->gfu_boost, + gf_group_bits); + + // Adjust KF group bits and error remaining. + twopass->kf_group_error_left -= (int64_t)gf_group_err; + + // If this is an arf update we want to remove the score for the overlay + // frame at the end which will usually be very cheap to code. + // The overlay frame has already, in effect, been coded so we want to spread + // the remaining bits among the other frames. + // For normal GFs remove the score for the GF itself unless this is + // also a key frame in which case it has already been accounted for. + if (rc->source_alt_ref_pending) { + gf_group_error_left = gf_group_err - mod_frame_err; + } else if (!is_intra_only) { + gf_group_error_left = gf_group_err - gf_first_frame_err; + } else { + gf_group_error_left = gf_group_err; + } + + // Set up the structure of this Group-Of-Pictures (same as GF_GROUP) + av1_gop_setup_structure(cpi, frame_params); + + // Allocate bits to each of the frames in the GF group. + allocate_gf_group_bits(cpi, gf_group_bits, gf_group_error_left, gf_arf_bits, + frame_params); + + // Reset the file position. + reset_fpf_position(twopass, start_pos); + + // Calculate a section intra ratio used in setting max loop filter. + if (frame_params->frame_type != KEY_FRAME) { + twopass->section_intra_rating = calculate_section_intra_ratio( + start_pos, twopass->stats_in_end, rc->baseline_gf_interval); + } +} + +// Minimum % intra coding observed in first pass (1.0 = 100%) +#define MIN_INTRA_LEVEL 0.25 +// Minimum ratio between the % of intra coding and inter coding in the first +// pass after discounting neutral blocks (discounting neutral blocks in this +// way helps catch scene cuts in clips with very flat areas or letter box +// format clips with image padding. +#define INTRA_VS_INTER_THRESH 2.0 +// Hard threshold where the first pass chooses intra for almost all blocks. +// In such a case even if the frame is not a scene cut coding a key frame +// may be a good option. +#define VERY_LOW_INTER_THRESH 0.05 +// Maximum threshold for the relative ratio of intra error score vs best +// inter error score. +#define KF_II_ERR_THRESHOLD 2.5 +// In real scene cuts there is almost always a sharp change in the intra +// or inter error score. +#define ERR_CHANGE_THRESHOLD 0.4 +// For real scene cuts we expect an improvment in the intra inter error +// ratio in the next frame. +#define II_IMPROVEMENT_THRESHOLD 3.5 +#define KF_II_MAX 128.0 + +// Threshold for use of the lagging second reference frame. High second ref +// usage may point to a transient event like a flash or occlusion rather than +// a real scene cut. +// We adapt the threshold based on number of frames in this key-frame group so +// far. +static double get_second_ref_usage_thresh(int frame_count_so_far) { + const int adapt_upto = 32; + const double min_second_ref_usage_thresh = 0.085; + const double second_ref_usage_thresh_max_delta = 0.035; + if (frame_count_so_far >= adapt_upto) { + return min_second_ref_usage_thresh + second_ref_usage_thresh_max_delta; + } + return min_second_ref_usage_thresh + + ((double)frame_count_so_far / (adapt_upto - 1)) * + second_ref_usage_thresh_max_delta; +} + +static int test_candidate_kf(TWO_PASS *twopass, + const FIRSTPASS_STATS *last_frame, + const FIRSTPASS_STATS *this_frame, + const FIRSTPASS_STATS *next_frame, + int frame_count_so_far) { + int is_viable_kf = 0; + double pcnt_intra = 1.0 - this_frame->pcnt_inter; + double modified_pcnt_inter = + this_frame->pcnt_inter - this_frame->pcnt_neutral; + const double second_ref_usage_thresh = + get_second_ref_usage_thresh(frame_count_so_far); + + // Does the frame satisfy the primary criteria of a key frame? + // See above for an explanation of the test criteria. + // If so, then examine how well it predicts subsequent frames. + if ((this_frame->pcnt_second_ref < second_ref_usage_thresh) && + (next_frame->pcnt_second_ref < second_ref_usage_thresh) && + ((this_frame->pcnt_inter < VERY_LOW_INTER_THRESH) || + ((pcnt_intra > MIN_INTRA_LEVEL) && + (pcnt_intra > (INTRA_VS_INTER_THRESH * modified_pcnt_inter)) && + ((this_frame->intra_error / + DOUBLE_DIVIDE_CHECK(this_frame->coded_error)) < + KF_II_ERR_THRESHOLD) && + ((fabs(last_frame->coded_error - this_frame->coded_error) / + DOUBLE_DIVIDE_CHECK(this_frame->coded_error) > + ERR_CHANGE_THRESHOLD) || + (fabs(last_frame->intra_error - this_frame->intra_error) / + DOUBLE_DIVIDE_CHECK(this_frame->intra_error) > + ERR_CHANGE_THRESHOLD) || + ((next_frame->intra_error / + DOUBLE_DIVIDE_CHECK(next_frame->coded_error)) > + II_IMPROVEMENT_THRESHOLD))))) { + int i; + const FIRSTPASS_STATS *start_pos = twopass->stats_in; + FIRSTPASS_STATS local_next_frame = *next_frame; + double boost_score = 0.0; + double old_boost_score = 0.0; + double decay_accumulator = 1.0; + + // Examine how well the key frame predicts subsequent frames. + for (i = 0; i < 16; ++i) { + double next_iiratio = (BOOST_FACTOR * local_next_frame.intra_error / + DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error)); + + if (next_iiratio > KF_II_MAX) next_iiratio = KF_II_MAX; + + // Cumulative effect of decay in prediction quality. + if (local_next_frame.pcnt_inter > 0.85) + decay_accumulator *= local_next_frame.pcnt_inter; + else + decay_accumulator *= (0.85 + local_next_frame.pcnt_inter) / 2.0; + + // Keep a running total. + boost_score += (decay_accumulator * next_iiratio); + + // Test various breakout clauses. + if ((local_next_frame.pcnt_inter < 0.05) || (next_iiratio < 1.5) || + (((local_next_frame.pcnt_inter - local_next_frame.pcnt_neutral) < + 0.20) && + (next_iiratio < 3.0)) || + ((boost_score - old_boost_score) < 3.0) || + (local_next_frame.intra_error < 200)) { + break; + } + + old_boost_score = boost_score; + + // Get the next frame details + if (EOF == input_stats(twopass, &local_next_frame)) break; + } + + // If there is tolerable prediction for at least the next 3 frames then + // break out else discard this potential key frame and move on + if (boost_score > 30.0 && (i > 3)) { + is_viable_kf = 1; + } else { + // Reset the file position + reset_fpf_position(twopass, start_pos); + + is_viable_kf = 0; + } + } + + return is_viable_kf; +} + +#define FRAMES_TO_CHECK_DECAY 8 +#define KF_MIN_FRAME_BOOST 80.0 +#define KF_MAX_FRAME_BOOST 128.0 +#define MIN_KF_BOOST 300 // Minimum boost for non-static KF interval +#define MIN_STATIC_KF_BOOST 5400 // Minimum boost for static KF interval + +static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { + int i, j; + RATE_CONTROL *const rc = &cpi->rc; + TWO_PASS *const twopass = &cpi->twopass; + GF_GROUP *const gf_group = &twopass->gf_group; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + const FIRSTPASS_STATS first_frame = *this_frame; + const FIRSTPASS_STATS *const start_position = twopass->stats_in; + FIRSTPASS_STATS next_frame; + FIRSTPASS_STATS last_frame; + int kf_bits = 0; + int loop_decay_counter = 0; + double decay_accumulator = 1.0; + double av_decay_accumulator = 0.0; + double zero_motion_accumulator = 1.0; + double boost_score = 0.0; + double kf_mod_err = 0.0; + double kf_group_err = 0.0; + double recent_loop_decay[FRAMES_TO_CHECK_DECAY]; + + av1_zero(next_frame); + + rc->frames_since_key = 0; + + // Reset the GF group data structures. + av1_zero(*gf_group); + + // Is this a forced key frame by interval. + rc->this_key_frame_forced = rc->next_key_frame_forced; + + // Clear the alt ref active flag and last group multi arf flags as they + // can never be set for a key frame. + rc->source_alt_ref_active = 0; + + // KF is always a GF so clear frames till next gf counter. + rc->frames_till_gf_update_due = 0; + + rc->frames_to_key = 1; + + twopass->kf_group_bits = 0; // Total bits available to kf group + twopass->kf_group_error_left = 0; // Group modified error score. + + kf_mod_err = calculate_modified_err(cpi, twopass, oxcf, this_frame); + + // Initialize the decay rates for the recent frames to check + for (j = 0; j < FRAMES_TO_CHECK_DECAY; ++j) recent_loop_decay[j] = 1.0; + + // Find the next keyframe. + i = 0; + while (twopass->stats_in < twopass->stats_in_end && + rc->frames_to_key < cpi->oxcf.key_freq) { + // Accumulate kf group error. + kf_group_err += calculate_modified_err(cpi, twopass, oxcf, this_frame); + + // Load the next frame's stats. + last_frame = *this_frame; + input_stats(twopass, this_frame); + + // Provided that we are not at the end of the file... + if (cpi->oxcf.auto_key && twopass->stats_in < twopass->stats_in_end) { + double loop_decay_rate; + + // Check for a scene cut. + if (test_candidate_kf(twopass, &last_frame, this_frame, twopass->stats_in, + rc->frames_to_key)) + break; + + // How fast is the prediction quality decaying? + loop_decay_rate = get_prediction_decay_rate(cpi, twopass->stats_in); + + // We want to know something about the recent past... rather than + // as used elsewhere where we are concerned with decay in prediction + // quality since the last GF or KF. + recent_loop_decay[i % FRAMES_TO_CHECK_DECAY] = loop_decay_rate; + decay_accumulator = 1.0; + for (j = 0; j < FRAMES_TO_CHECK_DECAY; ++j) + decay_accumulator *= recent_loop_decay[j]; + + // Special check for transition or high motion followed by a + // static scene. + if (detect_transition_to_still(cpi, i, cpi->oxcf.key_freq - i, + loop_decay_rate, decay_accumulator)) + break; + + // Step on to the next frame. + ++rc->frames_to_key; + + // If we don't have a real key frame within the next two + // key_freq intervals then break out of the loop. + if (rc->frames_to_key >= 2 * cpi->oxcf.key_freq) break; + } else { + ++rc->frames_to_key; + } + ++i; + } + + // If there is a max kf interval set by the user we must obey it. + // We already breakout of the loop above at 2x max. + // This code centers the extra kf if the actual natural interval + // is between 1x and 2x. + if (cpi->oxcf.auto_key && rc->frames_to_key > cpi->oxcf.key_freq) { + FIRSTPASS_STATS tmp_frame = first_frame; + + rc->frames_to_key /= 2; + + // Reset to the start of the group. + reset_fpf_position(twopass, start_position); + + kf_group_err = 0.0; + + // Rescan to get the correct error data for the forced kf group. + for (i = 0; i < rc->frames_to_key; ++i) { + kf_group_err += calculate_modified_err(cpi, twopass, oxcf, &tmp_frame); + input_stats(twopass, &tmp_frame); + } + rc->next_key_frame_forced = 1; + } else if (twopass->stats_in == twopass->stats_in_end || + rc->frames_to_key >= cpi->oxcf.key_freq) { + rc->next_key_frame_forced = 1; + } else { + rc->next_key_frame_forced = 0; + } + + // Special case for the last key frame of the file. + if (twopass->stats_in >= twopass->stats_in_end) { + // Accumulate kf group error. + kf_group_err += calculate_modified_err(cpi, twopass, oxcf, this_frame); + } + + // Calculate the number of bits that should be assigned to the kf group. + if (twopass->bits_left > 0 && twopass->modified_error_left > 0.0) { + // Maximum number of bits for a single normal frame (not key frame). + const int max_bits = frame_max_bits(rc, &cpi->oxcf); + + // Maximum number of bits allocated to the key frame group. + int64_t max_grp_bits; + + // Default allocation based on bits left and relative + // complexity of the section. + twopass->kf_group_bits = (int64_t)( + twopass->bits_left * (kf_group_err / twopass->modified_error_left)); + + // Clip based on maximum per frame rate defined by the user. + max_grp_bits = (int64_t)max_bits * (int64_t)rc->frames_to_key; + if (twopass->kf_group_bits > max_grp_bits) + twopass->kf_group_bits = max_grp_bits; + } else { + twopass->kf_group_bits = 0; + } + twopass->kf_group_bits = AOMMAX(0, twopass->kf_group_bits); + + // Reset the first pass file position. + reset_fpf_position(twopass, start_position); + + // Scan through the kf group collating various stats used to determine + // how many bits to spend on it. + decay_accumulator = 1.0; + boost_score = 0.0; + const double kf_max_boost = + cpi->oxcf.rc_mode == AOM_Q + ? AOMMIN(AOMMAX(rc->frames_to_key * 2.0, KF_MIN_FRAME_BOOST), + KF_MAX_FRAME_BOOST) + : KF_MAX_FRAME_BOOST; + for (i = 0; i < (rc->frames_to_key - 1); ++i) { + if (EOF == input_stats(twopass, &next_frame)) break; + + // Monitor for static sections. + // For the first frame in kf group, the second ref indicator is invalid. + if (i > 0) { + zero_motion_accumulator = AOMMIN( + zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame)); + } else { + zero_motion_accumulator = next_frame.pcnt_inter - next_frame.pcnt_motion; + } + + // Not all frames in the group are necessarily used in calculating boost. + if ((i <= rc->max_gf_interval) || + ((i <= (rc->max_gf_interval * 4)) && (decay_accumulator > 0.5))) { + const double frame_boost = + calc_frame_boost(cpi, this_frame, 0, kf_max_boost); + + // How fast is prediction quality decaying. + if (!detect_flash(twopass, 0)) { + const double loop_decay_rate = + get_prediction_decay_rate(cpi, &next_frame); + decay_accumulator *= loop_decay_rate; + decay_accumulator = AOMMAX(decay_accumulator, MIN_DECAY_FACTOR); + av_decay_accumulator += decay_accumulator; + ++loop_decay_counter; + } + boost_score += (decay_accumulator * frame_boost); + } + } + if (loop_decay_counter > 0) + av_decay_accumulator /= (double)loop_decay_counter; + + reset_fpf_position(twopass, start_position); + + // Store the zero motion percentage + twopass->kf_zeromotion_pct = (int)(zero_motion_accumulator * 100.0); + + // Calculate a section intra ratio used in setting max loop filter. + twopass->section_intra_rating = calculate_section_intra_ratio( + start_position, twopass->stats_in_end, rc->frames_to_key); + + rc->kf_boost = (int)(av_decay_accumulator * boost_score); + + // Special case for static / slide show content but don't apply + // if the kf group is very short. + if ((zero_motion_accumulator > STATIC_KF_GROUP_FLOAT_THRESH) && + (rc->frames_to_key > 8)) { + rc->kf_boost = AOMMAX(rc->kf_boost, MIN_STATIC_KF_BOOST); + } else { + // Apply various clamps for min and max boost + rc->kf_boost = AOMMAX(rc->kf_boost, (rc->frames_to_key * 3)); + rc->kf_boost = AOMMAX(rc->kf_boost, MIN_KF_BOOST); + } + + // Work out how many bits to allocate for the key frame itself. + kf_bits = calculate_boost_bits((rc->frames_to_key - 1), rc->kf_boost, + twopass->kf_group_bits); + // printf("kf boost = %d kf_bits = %d kf_zeromotion_pct = %d\n", rc->kf_boost, + // kf_bits, twopass->kf_zeromotion_pct); + + // Work out the fraction of the kf group bits reserved for the inter frames + // within the group after discounting the bits for the kf itself. + if (twopass->kf_group_bits) { + twopass->kfgroup_inter_fraction = + (double)(twopass->kf_group_bits - kf_bits) / + (double)twopass->kf_group_bits; + } else { + twopass->kfgroup_inter_fraction = 1.0; + } + + twopass->kf_group_bits -= kf_bits; + + // Save the bits to spend on the key frame. + gf_group->bit_allocation[0] = kf_bits; + gf_group->update_type[0] = KF_UPDATE; + + // Note the total error score of the kf group minus the key frame itself. + twopass->kf_group_error_left = (int)(kf_group_err - kf_mod_err); + + // Adjust the count of total modified error left. + // The count of bits left is adjusted elsewhere based on real coded frame + // sizes. + twopass->modified_error_left -= kf_group_err; +} + +static int is_skippable_frame(const AV1_COMP *cpi) { + // If the current frame does not have non-zero motion vector detected in the + // first pass, and so do its previous and forward frames, then this frame + // can be skipped for partition check, and the partition size is assigned + // according to the variance + const TWO_PASS *const twopass = &cpi->twopass; + + return (!frame_is_intra_only(&cpi->common) && + twopass->stats_in - 2 > twopass->stats_in_start && + twopass->stats_in < twopass->stats_in_end && + (twopass->stats_in - 1)->pcnt_inter - + (twopass->stats_in - 1)->pcnt_motion == + 1 && + (twopass->stats_in - 2)->pcnt_inter - + (twopass->stats_in - 2)->pcnt_motion == + 1 && + twopass->stats_in->pcnt_inter - twopass->stats_in->pcnt_motion == 1); +} + +#define ARF_STATS_OUTPUT 0 +#if ARF_STATS_OUTPUT +unsigned int arf_count = 0; +#endif +#define DEFAULT_GRP_WEIGHT 1.0 + +void av1_get_second_pass_params(AV1_COMP *cpi, + EncodeFrameParams *const frame_params, + unsigned int frame_flags) { + AV1_COMMON *const cm = &cpi->common; + CurrentFrame *const current_frame = &cm->current_frame; + RATE_CONTROL *const rc = &cpi->rc; + TWO_PASS *const twopass = &cpi->twopass; + GF_GROUP *const gf_group = &twopass->gf_group; + int frames_left; + FIRSTPASS_STATS this_frame; + + int target_rate; + + frames_left = (int)(twopass->total_stats.count - current_frame->frame_number); + + if (!twopass->stats_in) return; + + // If this is an arf frame then we dont want to read the stats file or + // advance the input pointer as we already have what we need. + if (gf_group->update_type[gf_group->index] == ARF_UPDATE || + gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) { + target_rate = gf_group->bit_allocation[gf_group->index]; + target_rate = av1_rc_clamp_pframe_target_size( + cpi, target_rate, gf_group->update_type[gf_group->index]); + rc->base_frame_target = target_rate; + + if (cpi->no_show_kf) { + assert(gf_group->update_type[gf_group->index] == ARF_UPDATE); + frame_params->frame_type = KEY_FRAME; + } else { + frame_params->frame_type = INTER_FRAME; + } + + // Do the firstpass stats indicate that this frame is skippable for the + // partition search? + if (cpi->sf.allow_partition_search_skip && cpi->oxcf.pass == 2) { + cpi->partition_search_skippable_frame = is_skippable_frame(cpi); + } + + return; + } + + aom_clear_system_state(); + + if (cpi->oxcf.rc_mode == AOM_Q) { + twopass->active_worst_quality = cpi->oxcf.cq_level; + } else if (current_frame->frame_number == 0) { + // Special case code for first frame. + const int section_target_bandwidth = + (int)(twopass->bits_left / frames_left); + const double section_length = twopass->total_left_stats.count; + const double section_error = + twopass->total_left_stats.coded_error / section_length; + const double section_intra_skip = + twopass->total_left_stats.intra_skip_pct / section_length; + const double section_inactive_zone = + (twopass->total_left_stats.inactive_zone_rows * 2) / + ((double)cm->mb_rows * section_length); + const int tmp_q = get_twopass_worst_quality( + cpi, section_error, section_intra_skip + section_inactive_zone, + section_target_bandwidth, DEFAULT_GRP_WEIGHT); + + twopass->active_worst_quality = tmp_q; + twopass->baseline_active_worst_quality = tmp_q; + rc->ni_av_qi = tmp_q; + rc->last_q[INTER_FRAME] = tmp_q; + rc->avg_q = av1_convert_qindex_to_q(tmp_q, cm->seq_params.bit_depth); + rc->avg_frame_qindex[INTER_FRAME] = tmp_q; + rc->last_q[KEY_FRAME] = (tmp_q + cpi->oxcf.best_allowed_q) / 2; + rc->avg_frame_qindex[KEY_FRAME] = rc->last_q[KEY_FRAME]; + } + + av1_zero(this_frame); + if (EOF == input_stats(twopass, &this_frame)) return; + + // Set the frame content type flag. + if (this_frame.intra_skip_pct >= FC_ANIMATION_THRESH) + twopass->fr_content_type = FC_GRAPHICS_ANIMATION; + else + twopass->fr_content_type = FC_NORMAL; + + // Keyframe and section processing. + if (rc->frames_to_key == 0 || (frame_flags & FRAMEFLAGS_KEY)) { + FIRSTPASS_STATS this_frame_copy; + this_frame_copy = this_frame; + frame_params->frame_type = KEY_FRAME; + // Define next KF group and assign bits to it. + find_next_key_frame(cpi, &this_frame); + this_frame = this_frame_copy; + } else { + frame_params->frame_type = INTER_FRAME; + } + + // Define a new GF/ARF group. (Should always enter here for key frames). + if (rc->frames_till_gf_update_due == 0) { + define_gf_group(cpi, &this_frame, frame_params); + + rc->frames_till_gf_update_due = rc->baseline_gf_interval; + +#if ARF_STATS_OUTPUT + { + FILE *fpfile; + fpfile = fopen("arf.stt", "a"); + ++arf_count; + fprintf(fpfile, "%10d %10d %10d %10d %10d\n", current_frame->frame_number, + rc->frames_till_gf_update_due, rc->kf_boost, arf_count, + rc->gfu_boost); + + fclose(fpfile); + } +#endif + } + + // Do the firstpass stats indicate that this frame is skippable for the + // partition search? + if (cpi->sf.allow_partition_search_skip && cpi->oxcf.pass == 2) { + cpi->partition_search_skippable_frame = is_skippable_frame(cpi); + } + + target_rate = gf_group->bit_allocation[gf_group->index]; + + if (frame_params->frame_type == KEY_FRAME) { + target_rate = av1_rc_clamp_iframe_target_size(cpi, target_rate); + } else { + target_rate = av1_rc_clamp_pframe_target_size( + cpi, target_rate, gf_group->update_type[gf_group->index]); + } + + rc->base_frame_target = target_rate; + + { + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) + ? cpi->initial_mbs + : cpi->common.MBs; + // The multiplication by 256 reverses a scaling factor of (>> 8) + // applied when combining MB error values for the frame. + twopass->mb_av_energy = log((this_frame.intra_error / num_mbs) + 1.0); + twopass->frame_avg_haar_energy = + log((this_frame.frame_avg_wavelet_energy / num_mbs) + 1.0); + } + + // Update the total stats remaining structure. + subtract_stats(&twopass->total_left_stats, &this_frame); +} + +void av1_init_second_pass(AV1_COMP *cpi) { + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + TWO_PASS *const twopass = &cpi->twopass; + double frame_rate; + FIRSTPASS_STATS *stats; + + av1_twopass_zero_stats(&twopass->total_stats); + av1_twopass_zero_stats(&twopass->total_left_stats); + + if (!twopass->stats_in_end) return; + + stats = &twopass->total_stats; + + *stats = *twopass->stats_in_end; + twopass->total_left_stats = *stats; + + frame_rate = 10000000.0 * stats->count / stats->duration; + // Each frame can have a different duration, as the frame rate in the source + // isn't guaranteed to be constant. The frame rate prior to the first frame + // encoded in the second pass is a guess. However, the sum duration is not. + // It is calculated based on the actual durations of all frames from the + // first pass. + av1_new_framerate(cpi, frame_rate); + twopass->bits_left = + (int64_t)(stats->duration * oxcf->target_bandwidth / 10000000.0); + + // This variable monitors how far behind the second ref update is lagging. + twopass->sr_update_lag = 1; + + // Scan the first pass file and calculate a modified total error based upon + // the bias/power function used to allocate bits. + { + const double avg_error = + stats->coded_error / DOUBLE_DIVIDE_CHECK(stats->count); + const FIRSTPASS_STATS *s = twopass->stats_in; + double modified_error_total = 0.0; + twopass->modified_error_min = + (avg_error * oxcf->two_pass_vbrmin_section) / 100; + twopass->modified_error_max = + (avg_error * oxcf->two_pass_vbrmax_section) / 100; + while (s < twopass->stats_in_end) { + modified_error_total += calculate_modified_err(cpi, twopass, oxcf, s); + ++s; + } + twopass->modified_error_left = modified_error_total; + } + + // Reset the vbr bits off target counters + cpi->rc.vbr_bits_off_target = 0; + cpi->rc.vbr_bits_off_target_fast = 0; + + cpi->rc.rate_error_estimate = 0; + + // Static sequence monitor variables. + twopass->kf_zeromotion_pct = 100; + twopass->last_kfgroup_zeromotion_pct = 100; +} + +#define MINQ_ADJ_LIMIT 48 +#define MINQ_ADJ_LIMIT_CQ 20 +#define HIGH_UNDERSHOOT_RATIO 2 +void av1_twopass_postencode_update(AV1_COMP *cpi) { + TWO_PASS *const twopass = &cpi->twopass; + RATE_CONTROL *const rc = &cpi->rc; + const int bits_used = rc->base_frame_target; + + // VBR correction is done through rc->vbr_bits_off_target. Based on the + // sign of this value, a limited % adjustment is made to the target rate + // of subsequent frames, to try and push it back towards 0. This method + // is designed to prevent extreme behaviour at the end of a clip + // or group of frames. + rc->vbr_bits_off_target += rc->base_frame_target - rc->projected_frame_size; + twopass->bits_left = AOMMAX(twopass->bits_left - bits_used, 0); + + // Calculate the pct rc error. + if (rc->total_actual_bits) { + rc->rate_error_estimate = + (int)((rc->vbr_bits_off_target * 100) / rc->total_actual_bits); + rc->rate_error_estimate = clamp(rc->rate_error_estimate, -100, 100); + } else { + rc->rate_error_estimate = 0; + } + + if (cpi->common.current_frame.frame_type != KEY_FRAME) { + twopass->kf_group_bits -= bits_used; + twopass->last_kfgroup_zeromotion_pct = twopass->kf_zeromotion_pct; + } + twopass->kf_group_bits = AOMMAX(twopass->kf_group_bits, 0); + + // If the rate control is drifting consider adjustment to min or maxq. + if ((cpi->oxcf.rc_mode != AOM_Q) && !cpi->rc.is_src_frame_alt_ref) { + const int maxq_adj_limit = + rc->worst_quality - twopass->active_worst_quality; + const int minq_adj_limit = + (cpi->oxcf.rc_mode == AOM_CQ ? MINQ_ADJ_LIMIT_CQ : MINQ_ADJ_LIMIT); + + // Undershoot. + if (rc->rate_error_estimate > cpi->oxcf.under_shoot_pct) { + --twopass->extend_maxq; + if (rc->rolling_target_bits >= rc->rolling_actual_bits) + ++twopass->extend_minq; + // Overshoot. + } else if (rc->rate_error_estimate < -cpi->oxcf.over_shoot_pct) { + --twopass->extend_minq; + if (rc->rolling_target_bits < rc->rolling_actual_bits) + ++twopass->extend_maxq; + } else { + // Adjustment for extreme local overshoot. + if (rc->projected_frame_size > (2 * rc->base_frame_target) && + rc->projected_frame_size > (2 * rc->avg_frame_bandwidth)) + ++twopass->extend_maxq; + + // Unwind undershoot or overshoot adjustment. + if (rc->rolling_target_bits < rc->rolling_actual_bits) + --twopass->extend_minq; + else if (rc->rolling_target_bits > rc->rolling_actual_bits) + --twopass->extend_maxq; + } + + twopass->extend_minq = clamp(twopass->extend_minq, 0, minq_adj_limit); + twopass->extend_maxq = clamp(twopass->extend_maxq, 0, maxq_adj_limit); + + // If there is a big and undexpected undershoot then feed the extra + // bits back in quickly. One situation where this may happen is if a + // frame is unexpectedly almost perfectly predicted by the ARF or GF + // but not very well predcited by the previous frame. + if (!frame_is_kf_gf_arf(cpi) && !cpi->rc.is_src_frame_alt_ref) { + int fast_extra_thresh = rc->base_frame_target / HIGH_UNDERSHOOT_RATIO; + if (rc->projected_frame_size < fast_extra_thresh) { + rc->vbr_bits_off_target_fast += + fast_extra_thresh - rc->projected_frame_size; + rc->vbr_bits_off_target_fast = + AOMMIN(rc->vbr_bits_off_target_fast, (4 * rc->avg_frame_bandwidth)); + + // Fast adaptation of minQ if necessary to use up the extra bits. + if (rc->avg_frame_bandwidth) { + twopass->extend_minq_fast = + (int)(rc->vbr_bits_off_target_fast * 8 / rc->avg_frame_bandwidth); + } + twopass->extend_minq_fast = AOMMIN( + twopass->extend_minq_fast, minq_adj_limit - twopass->extend_minq); + } else if (rc->vbr_bits_off_target_fast) { + twopass->extend_minq_fast = AOMMIN( + twopass->extend_minq_fast, minq_adj_limit - twopass->extend_minq); + } else { + twopass->extend_minq_fast = 0; + } + } + } +} diff --git a/third_party/aom/av1/encoder/pass2_strategy.h b/third_party/aom/av1/encoder/pass2_strategy.h new file mode 100644 index 0000000000..bf37746a1f --- /dev/null +++ b/third_party/aom/av1/encoder/pass2_strategy.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019, 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. + */ + +#ifndef AOM_AV1_ENCODER_PASS2_STRATEGY_H_ +#define AOM_AV1_ENCODER_PASS2_STRATEGY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct AV1_COMP; +struct EncodeFrameParams; + +void av1_init_second_pass(struct AV1_COMP *cpi); + +void av1_get_second_pass_params(struct AV1_COMP *cpi, + struct EncodeFrameParams *const frame_params, + unsigned int frame_flags); + +void av1_twopass_postencode_update(struct AV1_COMP *cpi); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_PASS2_STRATEGY_H_ diff --git a/third_party/aom/av1/encoder/picklpf.c b/third_party/aom/av1/encoder/picklpf.c index 8aeec0c08a..aca089c1e4 100644 --- a/third_party/aom/av1/encoder/picklpf.c +++ b/third_party/aom/av1/encoder/picklpf.c @@ -213,19 +213,25 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi, const int min_filter_level = 0; const int max_filter_level = av1_get_max_filter_level(cpi); const int q = av1_ac_quant_Q3(cm->base_qindex, 0, cm->seq_params.bit_depth); + // based on tests result for rtc test set + // 0.04590 boosted or 0.02295 non-booseted in 18-bit fixed point + const int strength_boost_q_treshold = 700; + const int inter_frame_multiplier = + q > strength_boost_q_treshold ? 12034 : 6017; // These values were determined by linear fitting the result of the // searched level for 8 bit depth: // Keyframes: filt_guess = q * 0.06699 - 1.60817 - // Other frames: filt_guess = q * 0.02295 + 2.48225 + // Other frames: filt_guess = q * inter_frame_multiplier + 2.48225 // // And high bit depth separately: // filt_guess = q * 0.316206 + 3.87252 int filt_guess; switch (cm->seq_params.bit_depth) { case AOM_BITS_8: - filt_guess = (cm->current_frame.frame_type == KEY_FRAME) - ? ROUND_POWER_OF_TWO(q * 17563 - 421574, 18) - : ROUND_POWER_OF_TWO(q * 6017 + 650707, 18); + filt_guess = + (cm->current_frame.frame_type == KEY_FRAME) + ? ROUND_POWER_OF_TWO(q * 17563 - 421574, 18) + : ROUND_POWER_OF_TWO(q * inter_frame_multiplier + 650707, 18); break; case AOM_BITS_10: filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20); diff --git a/third_party/aom/av1/encoder/pickrst.c b/third_party/aom/av1/encoder/pickrst.c index 39db3d2ea8..1b4f26c57b 100644 --- a/third_party/aom/av1/encoder/pickrst.c +++ b/third_party/aom/av1/encoder/pickrst.c @@ -1413,20 +1413,22 @@ void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi) { RestorationType best_rtype = RESTORE_NONE; const int highbd = rsc.cm->seq_params.use_highbitdepth; - extend_frame(rsc.dgd_buffer, rsc.plane_width, rsc.plane_height, - rsc.dgd_stride, RESTORATION_BORDER, RESTORATION_BORDER, - highbd); + if (!cpi->sf.disable_loop_restoration_chroma || !plane) { + extend_frame(rsc.dgd_buffer, rsc.plane_width, rsc.plane_height, + rsc.dgd_stride, RESTORATION_BORDER, RESTORATION_BORDER, + highbd); - for (RestorationType r = 0; r < num_rtypes; ++r) { - if ((force_restore_type != RESTORE_TYPES) && (r != RESTORE_NONE) && - (r != force_restore_type)) - continue; + for (RestorationType r = 0; r < num_rtypes; ++r) { + if ((force_restore_type != RESTORE_TYPES) && (r != RESTORE_NONE) && + (r != force_restore_type)) + continue; - double cost = search_rest_type(&rsc, r); + double cost = search_rest_type(&rsc, r); - if (r == 0 || cost < best_cost) { - best_cost = cost; - best_rtype = r; + if (r == 0 || cost < best_cost) { + best_cost = cost; + best_rtype = r; + } } } diff --git a/third_party/aom/av1/encoder/ratectrl.c b/third_party/aom/av1/encoder/ratectrl.c index 6a7637154d..861c7373ca 100644 --- a/third_party/aom/av1/encoder/ratectrl.c +++ b/third_party/aom/av1/encoder/ratectrl.c @@ -30,6 +30,7 @@ #include "av1/encoder/encodemv.h" #include "av1/encoder/encode_strategy.h" +#include "av1/encoder/gop_structure.h" #include "av1/encoder/random.h" #include "av1/encoder/ratectrl.h" @@ -97,18 +98,13 @@ static double resize_rate_factor(const AV1_COMP *cpi, int width, int height) { // fit to the original data (after plotting real maxq vs minq (not q index)) static int get_minq_index(double maxq, double x3, double x2, double x1, aom_bit_depth_t bit_depth) { - int i; const double minqtarget = AOMMIN(((x3 * maxq + x2) * maxq + x1) * maxq, maxq); // Special case handling to deal with the step from q2.0 // down to lossless mode represented by q 1.0. if (minqtarget <= 2.0) return 0; - for (i = 0; i < QINDEX_RANGE; i++) { - if (minqtarget <= av1_convert_qindex_to_q(i, bit_depth)) return i; - } - - return QINDEX_RANGE - 1; + return av1_find_qindex(minqtarget, bit_depth, 0, QINDEX_RANGE - 1); } static void init_minq_luts(int *kf_low_m, int *kf_high_m, int *arfgf_low, @@ -175,13 +171,15 @@ int av1_estimate_bits_at_q(FRAME_TYPE frame_type, int q, int mbs, (int)((uint64_t)bpm * mbs) >> BPER_MB_NORMBITS); } -int av1_rc_clamp_pframe_target_size(const AV1_COMP *const cpi, int target) { +int av1_rc_clamp_pframe_target_size(const AV1_COMP *const cpi, int target, + FRAME_UPDATE_TYPE frame_update_type) { const RATE_CONTROL *rc = &cpi->rc; const AV1EncoderConfig *oxcf = &cpi->oxcf; const int min_frame_target = AOMMAX(rc->min_frame_bandwidth, rc->avg_frame_bandwidth >> 5); // Clip the frame target to the minimum setup value. - if (cpi->rc.is_src_frame_alt_ref) { + if (frame_update_type == OVERLAY_UPDATE || + frame_update_type == INTNL_OVERLAY_UPDATE) { // If there is an active ARF at this location use the minimum // bits on this frame even if it is a constructed arf. // The active maximum quantizer insures that an appropriate @@ -220,9 +218,7 @@ static void update_buffer_level(AV1_COMP *cpi, int encoded_frame_size) { RATE_CONTROL *const rc = &cpi->rc; // Non-viewable frames are a special case and are treated as pure overhead. - // TODO(zoeliu): To further explore whether we should treat BWDREF_FRAME - // differently, since it is a no-show frame. - if (!cm->show_frame && !rc->is_bwd_ref_frame) + if (!cm->show_frame) rc->bits_off_target -= encoded_frame_size; else rc->bits_off_target += rc->avg_frame_bandwidth - encoded_frame_size; @@ -251,10 +247,10 @@ int av1_rc_get_default_min_gf_interval(int width, int height, // 4K60: 12 } -int av1_rc_get_default_max_gf_interval(double framerate, int min_gf_interval, - int max_pyr_height) { +int av1_rc_get_default_max_gf_interval(double framerate, int min_gf_interval) { int interval = AOMMIN(MAX_GF_INTERVAL, (int)(framerate * 0.75)); - interval = AOMMAX(av1_rc_get_fixed_gf_length(max_pyr_height), interval); + interval += (interval & 0x01); // Round to even value + interval = AOMMAX(MAX_GF_INTERVAL, interval); return AOMMAX(interval, min_gf_interval); } @@ -311,7 +307,7 @@ void av1_rc_init(const AV1EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) { oxcf->width, oxcf->height, oxcf->init_framerate); if (rc->max_gf_interval == 0) rc->max_gf_interval = av1_rc_get_default_max_gf_interval( - oxcf->init_framerate, rc->min_gf_interval, oxcf->gf_max_pyr_height); + oxcf->init_framerate, rc->min_gf_interval); rc->baseline_gf_interval = (rc->min_gf_interval + rc->max_gf_interval) / 2; } @@ -351,6 +347,22 @@ int av1_rc_drop_frame(AV1_COMP *cpi) { } } +static const RATE_FACTOR_LEVEL rate_factor_levels[FRAME_UPDATE_TYPES] = { + KF_STD, // KF_UPDATE + INTER_NORMAL, // LF_UPDATE + GF_ARF_STD, // GF_UPDATE + GF_ARF_STD, // ARF_UPDATE + INTER_NORMAL, // OVERLAY_UPDATE + INTER_NORMAL, // INTNL_OVERLAY_UPDATE + GF_ARF_LOW, // INTNL_ARF_UPDATE +}; + +static RATE_FACTOR_LEVEL get_rate_factor_level(const GF_GROUP *const gf_group) { + const FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_group->index]; + assert(update_type < FRAME_UPDATE_TYPES); + return rate_factor_levels[update_type]; +} + static double get_rate_correction_factor(const AV1_COMP *cpi, int width, int height) { const RATE_CONTROL *const rc = &cpi->rc; @@ -359,8 +371,8 @@ static double get_rate_correction_factor(const AV1_COMP *cpi, int width, if (cpi->common.current_frame.frame_type == KEY_FRAME) { rcf = rc->rate_correction_factors[KF_STD]; } else if (cpi->oxcf.pass == 2) { - RATE_FACTOR_LEVEL rf_lvl = - cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index]; + const RATE_FACTOR_LEVEL rf_lvl = + get_rate_factor_level(&cpi->twopass.gf_group); rcf = rc->rate_correction_factors[rf_lvl]; } else { if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) && @@ -386,8 +398,8 @@ static void set_rate_correction_factor(AV1_COMP *cpi, double factor, int width, if (cpi->common.current_frame.frame_type == KEY_FRAME) { rc->rate_correction_factors[KF_STD] = factor; } else if (cpi->oxcf.pass == 2) { - RATE_FACTOR_LEVEL rf_lvl = - cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index]; + const RATE_FACTOR_LEVEL rf_lvl = + get_rate_factor_level(&cpi->twopass.gf_group); rc->rate_correction_factors[rf_lvl] = factor; } else { if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) && @@ -473,45 +485,82 @@ void av1_rc_update_rate_correction_factors(AV1_COMP *cpi, int width, set_rate_correction_factor(cpi, rate_correction_factor, width, height); } +// Calculate rate for the given 'q'. +static int get_bits_per_mb(const AV1_COMP *cpi, int use_cyclic_refresh, + double correction_factor, int q) { + const AV1_COMMON *const cm = &cpi->common; + return use_cyclic_refresh + ? av1_cyclic_refresh_rc_bits_per_mb(cpi, q, correction_factor) + : av1_rc_bits_per_mb(cm->current_frame.frame_type, q, + correction_factor, cm->seq_params.bit_depth); +} + +// Similar to find_qindex_by_rate() function in ratectrl.c, but returns the q +// index with rate just above or below the desired rate, depending on which of +// the two rates is closer to the desired rate. +// Also, respects the selected aq_mode when computing the rate. +static int find_closest_qindex_by_rate(int desired_bits_per_mb, + const AV1_COMP *cpi, + double correction_factor, + int best_qindex, int worst_qindex) { + const int use_cyclic_refresh = + cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cpi->common.seg.enabled; + + // Find 'qindex' based on 'desired_bits_per_mb'. + assert(best_qindex <= worst_qindex); + int low = best_qindex; + int high = worst_qindex; + while (low < high) { + const int mid = (low + high) >> 1; + const int mid_bits_per_mb = + get_bits_per_mb(cpi, use_cyclic_refresh, correction_factor, mid); + if (mid_bits_per_mb > desired_bits_per_mb) { + low = mid + 1; + } else { + high = mid; + } + } + assert(low == high); + + // Calculate rate difference of this q index from the desired rate. + const int curr_q = low; + const int curr_bits_per_mb = + get_bits_per_mb(cpi, use_cyclic_refresh, correction_factor, curr_q); + const int curr_bit_diff = (curr_bits_per_mb <= desired_bits_per_mb) + ? desired_bits_per_mb - curr_bits_per_mb + : INT_MAX; + assert((curr_bit_diff != INT_MAX && curr_bit_diff >= 0) || + curr_q == worst_qindex); + + // Calculate rate difference for previous q index too. + const int prev_q = curr_q - 1; + int prev_bit_diff; + if (curr_bit_diff == INT_MAX || curr_q == best_qindex) { + prev_bit_diff = INT_MAX; + } else { + const int prev_bits_per_mb = + get_bits_per_mb(cpi, use_cyclic_refresh, correction_factor, prev_q); + assert(prev_bits_per_mb > desired_bits_per_mb); + prev_bit_diff = prev_bits_per_mb - desired_bits_per_mb; + } + + // Pick one of the two q indices, depending on which one has rate closer to + // the desired rate. + return (curr_bit_diff <= prev_bit_diff) ? curr_q : prev_q; +} + int av1_rc_regulate_q(const AV1_COMP *cpi, int target_bits_per_frame, int active_best_quality, int active_worst_quality, int width, int height) { - const AV1_COMMON *const cm = &cpi->common; - int q = active_worst_quality; - int last_error = INT_MAX; - int i, target_bits_per_mb, bits_per_mb_at_this_q; const int MBs = av1_get_MBs(width, height); const double correction_factor = get_rate_correction_factor(cpi, width, height); - - // Calculate required scaling factor based on target frame size and size of - // frame produced using previous Q. - target_bits_per_mb = + const int target_bits_per_mb = (int)((uint64_t)(target_bits_per_frame) << BPER_MB_NORMBITS) / MBs; - i = active_best_quality; - - do { - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled) { - bits_per_mb_at_this_q = - (int)av1_cyclic_refresh_rc_bits_per_mb(cpi, i, correction_factor); - } else { - bits_per_mb_at_this_q = - (int)av1_rc_bits_per_mb(cm->current_frame.frame_type, i, - correction_factor, cm->seq_params.bit_depth); - } - - if (bits_per_mb_at_this_q <= target_bits_per_mb) { - if ((target_bits_per_mb - bits_per_mb_at_this_q) <= last_error) - q = i; - else - q = i - 1; - - break; - } else { - last_error = bits_per_mb_at_this_q - target_bits_per_mb; - } - } while (++i <= active_worst_quality); + int q = + find_closest_qindex_by_rate(target_bits_per_mb, cpi, correction_factor, + active_best_quality, active_worst_quality); // In CBR mode, this makes sure q is between oscillating Qs to prevent // resonance. @@ -936,15 +985,20 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width, return q; } -int av1_frame_type_qdelta(const AV1_COMP *cpi, int rf_level, int q) { - static const FRAME_TYPE frame_type[RATE_FACTOR_LEVELS] = { - INTER_FRAME, INTER_FRAME, INTER_FRAME, INTER_FRAME, INTER_FRAME, KEY_FRAME - }; - const AV1_COMMON *const cm = &cpi->common; - int qdelta = av1_compute_qdelta_by_rate(&cpi->rc, frame_type[rf_level], q, - rate_factor_deltas[rf_level], - cm->seq_params.bit_depth); - return qdelta; +static const double rate_factor_deltas[RATE_FACTOR_LEVELS] = { + 1.00, // INTER_NORMAL + 1.25, // GF_ARF_LOW + 2.00, // GF_ARF_STD + 2.00, // KF_STD +}; + +int av1_frame_type_qdelta(const AV1_COMP *cpi, int q) { + const RATE_FACTOR_LEVEL rf_lvl = + get_rate_factor_level(&cpi->twopass.gf_group); + const FRAME_TYPE frame_type = (rf_lvl == KF_STD) ? KEY_FRAME : INTER_FRAME; + return av1_compute_qdelta_by_rate(&cpi->rc, frame_type, q, + rate_factor_deltas[rf_lvl], + cpi->common.seq_params.bit_depth); } #define STATIC_MOTION_THRESH 95 @@ -974,6 +1028,18 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, // as q. active_best_quality = cq_level; active_worst_quality = cq_level; + } else if (cm->current_frame.frame_type == KEY_FRAME && + cm->show_frame == 0) { + // Handle the special case for forward reference key frames. + // Increase the boost because this keyframe is used as a forward and + // backward reference. + const int qindex = rc->last_boosted_qindex; + const double last_boosted_q = av1_convert_qindex_to_q(qindex, bit_depth); + const int delta_qindex = av1_compute_qdelta( + rc, last_boosted_q, last_boosted_q * 0.25, bit_depth); + active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality); + // Update the arf_q since the forward keyframe is replacing the ALTREF + *arf_q = active_best_quality; } else if (rc->this_key_frame_forced) { // Handle the special case for key frames forced when we have reached // the maximum key frame interval. Here force the Q to a range @@ -991,13 +1057,10 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, active_worst_quality = AOMMIN(qindex + delta_qindex, active_worst_quality); } else { - // Increase the boost if the forced keyframe is a forward reference. - // These numbers were derived empirically. - const double boost_factor = cpi->oxcf.fwd_kf_enabled ? 0.25 : 0.50; qindex = rc->last_boosted_qindex; last_boosted_q = av1_convert_qindex_to_q(qindex, bit_depth); - delta_qindex = av1_compute_qdelta( - rc, last_boosted_q, last_boosted_q * boost_factor, bit_depth); + delta_qindex = av1_compute_qdelta(rc, last_boosted_q, + last_boosted_q * 0.50, bit_depth); active_best_quality = AOMMAX(qindex + delta_qindex, rc->best_quality); } } else { @@ -1048,16 +1111,13 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, // Constrained quality use slightly lower active best. active_best_quality = active_best_quality * 15 / 16; - if (gf_group->update_type[gf_group->index] == ARF_UPDATE || - (is_intrl_arf_boost && !cpi->new_bwdref_update_rule)) { - if (gf_group->update_type[gf_group->index] == ARF_UPDATE) { - const int min_boost = get_gf_high_motion_quality(q, bit_depth); - const int boost = min_boost - active_best_quality; + if (gf_group->update_type[gf_group->index] == ARF_UPDATE) { + const int min_boost = get_gf_high_motion_quality(q, bit_depth); + const int boost = min_boost - active_best_quality; - active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor); - } + active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor); *arf_q = active_best_quality; - } else if (cpi->new_bwdref_update_rule && is_intrl_arf_boost) { + } else if (is_intrl_arf_boost) { assert(rc->arf_q >= 0); // Ensure it is set to a valid value. active_best_quality = rc->arf_q; int this_height = gf_group_pyramid_level(cpi); @@ -1072,26 +1132,20 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, } else { if (gf_group->update_type[gf_group->index] == ARF_UPDATE) { active_best_quality = get_gf_active_quality(rc, q, bit_depth); - *arf_q = active_best_quality; const int min_boost = get_gf_high_motion_quality(q, bit_depth); const int boost = min_boost - active_best_quality; active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor); + *arf_q = active_best_quality; } else { assert(rc->arf_q >= 0); // Ensure it is set to a valid value. + assert(is_intrl_arf_boost); active_best_quality = rc->arf_q; - } - if (cpi->new_bwdref_update_rule && is_intrl_arf_boost) { int this_height = gf_group_pyramid_level(cpi); while (this_height < gf_group->pyramid_height) { active_best_quality = (active_best_quality + cq_level + 1) / 2; ++this_height; } - } else { - // Modify best quality for second level arfs. For mode AOM_Q this - // becomes the baseline frame q. - if (gf_group->rf_level[gf_group->index] == GF_ARF_LOW) - active_best_quality = (active_best_quality + cq_level + 1) / 2; } } } else { @@ -1100,7 +1154,7 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, const int boost = min_boost - active_best_quality; active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor); - if (cpi->new_bwdref_update_rule && is_intrl_arf_boost) { + if (is_intrl_arf_boost) { int this_height = gf_group_pyramid_level(cpi); while (this_height < gf_group->pyramid_height) { active_best_quality = @@ -1125,8 +1179,7 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, // Extension to max or min Q if undershoot or overshoot is outside // the permitted range. - if ((cpi->oxcf.rc_mode != AOM_Q) && - (cpi->twopass.gf_zeromotion_pct < VLOW_MOTION_THRESHOLD)) { + if (cpi->oxcf.rc_mode != AOM_Q) { if (frame_is_intra_only(cm) || (!rc->is_src_frame_alt_ref && (cpi->refresh_golden_frame || is_intrl_arf_boost || @@ -1145,8 +1198,7 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, // Static forced key frames Q restrictions dealt with elsewhere. if (!(frame_is_intra_only(cm)) || !rc->this_key_frame_forced || (cpi->twopass.last_kfgroup_zeromotion_pct < STATIC_MOTION_THRESH)) { - int qdelta = av1_frame_type_qdelta(cpi, gf_group->rf_level[gf_group->index], - active_worst_quality); + const int qdelta = av1_frame_type_qdelta(cpi, active_worst_quality); active_worst_quality = AOMMAX(active_worst_quality + qdelta, active_best_quality); } @@ -1166,7 +1218,8 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, if (oxcf->rc_mode == AOM_Q || (frame_is_intra_only(cm) && !rc->this_key_frame_forced && - cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH)) { + cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH && + rc->frames_to_key > 1)) { q = active_best_quality; // Special case code to try and match quality with forced key frames. } else if (frame_is_intra_only(cm) && rc->this_key_frame_forced) { @@ -1287,9 +1340,10 @@ static void update_golden_frame_stats(AV1_COMP *cpi) { // updated and cpi->refresh_golden_frame will still be zero. if (cpi->refresh_golden_frame || rc->is_src_frame_alt_ref) { // We will not use internal overlay frames to replace the golden frame - if (!rc->is_src_frame_ext_arf) + if (!rc->is_src_frame_internal_arf) { // this frame refreshes means next frames don't unless specified by user rc->frames_since_golden = 0; + } // If we are not using alt ref in the up and coming group clear the arf // active flag. In multi arf group case, if the index is not 0 then @@ -1305,32 +1359,6 @@ static void update_golden_frame_stats(AV1_COMP *cpi) { } } -void av1_estimate_qp_gop(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - int gop_length = cpi->rc.baseline_gf_interval; - int bottom_index, top_index; - int idx; - const int gf_index = cpi->twopass.gf_group.index; - - for (idx = 1; idx <= gop_length + 1 && idx < MAX_LAG_BUFFERS; ++idx) { - TplDepFrame *tpl_frame = &cpi->tpl_stats[idx]; - int target_rate = cpi->twopass.gf_group.bit_allocation[idx]; - int arf_q = 0; - - cpi->twopass.gf_group.index = idx; - rc_set_frame_target(cpi, target_rate, cm->width, cm->height); - av1_configure_buffer_updates( - cpi, cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]); - tpl_frame->base_qindex = rc_pick_q_and_bounds_two_pass( - cpi, cm->width, cm->height, &bottom_index, &top_index, &arf_q); - tpl_frame->base_qindex = AOMMAX(tpl_frame->base_qindex, 1); - } - // Reset the actual index and frame update - cpi->twopass.gf_group.index = gf_index; - av1_configure_buffer_updates( - cpi, cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]); -} - void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) { const AV1_COMMON *const cm = &cpi->common; const CurrentFrame *const current_frame = &cm->current_frame; @@ -1411,10 +1439,7 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) { // Actual bits spent rc->total_actual_bits += rc->projected_frame_size; - // TODO(zoeliu): To investigate whether we should treat BWDREF_FRAME - // differently here for rc->avg_frame_bandwidth. - rc->total_target_bits += - (cm->show_frame || rc->is_bwd_ref_frame) ? rc->avg_frame_bandwidth : 0; + rc->total_target_bits += cm->show_frame ? rc->avg_frame_bandwidth : 0; rc->total_target_vs_actual = rc->total_actual_bits - rc->total_target_bits; @@ -1447,22 +1472,24 @@ void av1_rc_postencode_update_drop_frame(AV1_COMP *cpi) { // Use this macro to turn on/off use of alt-refs in one-pass mode. #define USE_ALTREF_FOR_ONE_PASS 1 -static int calc_pframe_target_size_one_pass_vbr(const AV1_COMP *const cpi) { +static int calc_pframe_target_size_one_pass_vbr( + const AV1_COMP *const cpi, FRAME_UPDATE_TYPE frame_update_type) { static const int af_ratio = 10; const RATE_CONTROL *const rc = &cpi->rc; int target; #if USE_ALTREF_FOR_ONE_PASS - target = - (!rc->is_src_frame_alt_ref && - (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) - ? (rc->avg_frame_bandwidth * rc->baseline_gf_interval * af_ratio) / - (rc->baseline_gf_interval + af_ratio - 1) - : (rc->avg_frame_bandwidth * rc->baseline_gf_interval) / - (rc->baseline_gf_interval + af_ratio - 1); + if (frame_update_type == KF_UPDATE || frame_update_type == GF_UPDATE || + frame_update_type == ARF_UPDATE) { + target = (rc->avg_frame_bandwidth * rc->baseline_gf_interval * af_ratio) / + (rc->baseline_gf_interval + af_ratio - 1); + } else { + target = (rc->avg_frame_bandwidth * rc->baseline_gf_interval) / + (rc->baseline_gf_interval + af_ratio - 1); + } #else target = rc->avg_frame_bandwidth; #endif - return av1_rc_clamp_pframe_target_size(cpi, target); + return av1_rc_clamp_pframe_target_size(cpi, target, frame_update_type); } static int calc_iframe_target_size_one_pass_vbr(const AV1_COMP *const cpi) { @@ -1473,7 +1500,9 @@ static int calc_iframe_target_size_one_pass_vbr(const AV1_COMP *const cpi) { } void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi, - EncodeFrameParams *const frame_params) { + FRAME_UPDATE_TYPE *const frame_update_type, + EncodeFrameParams *const frame_params, + unsigned int frame_flags) { AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; CurrentFrame *const current_frame = &cm->current_frame; @@ -1483,10 +1512,9 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi, int sframe_mode = cpi->oxcf.sframe_mode; int sframe_enabled = cpi->oxcf.sframe_enabled; // TODO(yaowu): replace the "auto_key && 0" below with proper decision logic. - if (!cpi->refresh_alt_ref_frame && - (current_frame->frame_number == 0 || - (cpi->frame_flags & FRAMEFLAGS_KEY) || rc->frames_to_key == 0 || - (cpi->oxcf.auto_key && 0))) { + if (*frame_update_type != ARF_UPDATE && + (current_frame->frame_number == 0 || (frame_flags & FRAMEFLAGS_KEY) || + rc->frames_to_key == 0 || (cpi->oxcf.auto_key && 0))) { frame_params->frame_type = KEY_FRAME; rc->this_key_frame_forced = current_frame->frame_number != 0 && rc->frames_to_key == 0; @@ -1501,7 +1529,8 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi, // sframe_mode == 1: insert sframe if it matches altref frame. if (current_frame->frame_number % sframe_dist == 0 && - current_frame->frame_number != 0 && cpi->refresh_alt_ref_frame) { + current_frame->frame_number != 0 && + *frame_update_type == ARF_UPDATE) { frame_params->frame_type = S_FRAME; } } else { @@ -1513,7 +1542,7 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi, rc->sframe_due = 1; } - if (rc->sframe_due && cpi->refresh_alt_ref_frame) { + if (rc->sframe_due && *frame_update_type == ARF_UPDATE) { frame_params->frame_type = S_FRAME; rc->sframe_due = 0; } @@ -1536,7 +1565,7 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi, } else { rc->constrained_gf_group = 0; } - cpi->refresh_golden_frame = 1; + if (*frame_update_type == LF_UPDATE) *frame_update_type = GF_UPDATE; rc->source_alt_ref_pending = USE_ALTREF_FOR_ONE_PASS; rc->gfu_boost = DEFAULT_GF_BOOST; } @@ -1547,11 +1576,12 @@ void av1_rc_get_one_pass_vbr_params(AV1_COMP *cpi, if (frame_params->frame_type == KEY_FRAME) target = calc_iframe_target_size_one_pass_vbr(cpi); else - target = calc_pframe_target_size_one_pass_vbr(cpi); + target = calc_pframe_target_size_one_pass_vbr(cpi, *frame_update_type); rc_set_frame_target(cpi, target, cm->width, cm->height); } -static int calc_pframe_target_size_one_pass_cbr(const AV1_COMP *cpi) { +static int calc_pframe_target_size_one_pass_cbr( + const AV1_COMP *cpi, FRAME_UPDATE_TYPE frame_update_type) { const AV1EncoderConfig *oxcf = &cpi->oxcf; const RATE_CONTROL *rc = &cpi->rc; const int64_t diff = rc->optimal_buffer_level - rc->buffer_level; @@ -1562,12 +1592,14 @@ static int calc_pframe_target_size_one_pass_cbr(const AV1_COMP *cpi) { if (oxcf->gf_cbr_boost_pct) { const int af_ratio_pct = oxcf->gf_cbr_boost_pct + 100; - target = cpi->refresh_golden_frame - ? (rc->avg_frame_bandwidth * rc->baseline_gf_interval * - af_ratio_pct) / - (rc->baseline_gf_interval * 100 + af_ratio_pct - 100) - : (rc->avg_frame_bandwidth * rc->baseline_gf_interval * 100) / - (rc->baseline_gf_interval * 100 + af_ratio_pct - 100); + if (frame_update_type == GF_UPDATE || frame_update_type == OVERLAY_UPDATE) { + target = + (rc->avg_frame_bandwidth * rc->baseline_gf_interval * af_ratio_pct) / + (rc->baseline_gf_interval * 100 + af_ratio_pct - 100); + } else { + target = (rc->avg_frame_bandwidth * rc->baseline_gf_interval * 100) / + (rc->baseline_gf_interval * 100 + af_ratio_pct - 100); + } } else { target = rc->avg_frame_bandwidth; } @@ -1611,15 +1643,16 @@ static int calc_iframe_target_size_one_pass_cbr(const AV1_COMP *cpi) { } void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi, - EncodeFrameParams *const frame_params) { + FRAME_UPDATE_TYPE *const frame_update_type, + EncodeFrameParams *const frame_params, + unsigned int frame_flags) { AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; CurrentFrame *const current_frame = &cm->current_frame; int target; // TODO(yaowu): replace the "auto_key && 0" below with proper decision logic. - if ((current_frame->frame_number == 0 || - (cpi->frame_flags & FRAMEFLAGS_KEY) || rc->frames_to_key == 0 || - (cpi->oxcf.auto_key && 0))) { + if ((current_frame->frame_number == 0 || (frame_flags & FRAMEFLAGS_KEY) || + rc->frames_to_key == 0 || (cpi->oxcf.auto_key && 0))) { frame_params->frame_type = KEY_FRAME; rc->this_key_frame_forced = current_frame->frame_number != 0 && rc->frames_to_key == 0; @@ -1639,7 +1672,7 @@ void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi, // NOTE: frames_till_gf_update_due must be <= frames_to_key. if (rc->frames_till_gf_update_due > rc->frames_to_key) rc->frames_till_gf_update_due = rc->frames_to_key; - cpi->refresh_golden_frame = 1; + if (*frame_update_type == LF_UPDATE) *frame_update_type = GF_UPDATE; rc->gfu_boost = DEFAULT_GF_BOOST; } @@ -1651,39 +1684,72 @@ void av1_rc_get_one_pass_cbr_params(AV1_COMP *cpi, if (frame_params->frame_type == KEY_FRAME) target = calc_iframe_target_size_one_pass_cbr(cpi); else - target = calc_pframe_target_size_one_pass_cbr(cpi); + target = calc_pframe_target_size_one_pass_cbr(cpi, *frame_update_type); rc_set_frame_target(cpi, target, cm->width, cm->height); // TODO(afergs): Decide whether to scale up, down, or not at all } +int av1_find_qindex(double desired_q, aom_bit_depth_t bit_depth, + int best_qindex, int worst_qindex) { + assert(best_qindex <= worst_qindex); + int low = best_qindex; + int high = worst_qindex; + while (low < high) { + const int mid = (low + high) >> 1; + const double mid_q = av1_convert_qindex_to_q(mid, bit_depth); + if (mid_q < desired_q) { + low = mid + 1; + } else { + high = mid; + } + } + assert(low == high); + assert(av1_convert_qindex_to_q(low, bit_depth) >= desired_q || + low == worst_qindex); + return low; +} + int av1_compute_qdelta(const RATE_CONTROL *rc, double qstart, double qtarget, aom_bit_depth_t bit_depth) { - int start_index = rc->worst_quality; - int target_index = rc->worst_quality; - int i; - - // Convert the average q value to an index. - for (i = rc->best_quality; i < rc->worst_quality; ++i) { - start_index = i; - if (av1_convert_qindex_to_q(i, bit_depth) >= qstart) break; - } - - // Convert the q target to an index - for (i = rc->best_quality; i < rc->worst_quality; ++i) { - target_index = i; - if (av1_convert_qindex_to_q(i, bit_depth) >= qtarget) break; - } - + const int start_index = + av1_find_qindex(qstart, bit_depth, rc->best_quality, rc->worst_quality); + const int target_index = + av1_find_qindex(qtarget, bit_depth, rc->best_quality, rc->worst_quality); return target_index - start_index; } +// Find q_index for the desired_bits_per_mb, within [best_qindex, worst_qindex], +// assuming 'correction_factor' is 1.0. +// To be precise, 'q_index' is the smallest integer, for which the corresponding +// bits per mb <= desired_bits_per_mb. +// If no such q index is found, returns 'worst_qindex'. +static int find_qindex_by_rate(int desired_bits_per_mb, + aom_bit_depth_t bit_depth, FRAME_TYPE frame_type, + int best_qindex, int worst_qindex) { + assert(best_qindex <= worst_qindex); + int low = best_qindex; + int high = worst_qindex; + while (low < high) { + const int mid = (low + high) >> 1; + const int mid_bits_per_mb = + av1_rc_bits_per_mb(frame_type, mid, 1.0, bit_depth); + if (mid_bits_per_mb > desired_bits_per_mb) { + low = mid + 1; + } else { + high = mid; + } + } + assert(low == high); + assert(av1_rc_bits_per_mb(frame_type, low, 1.0, bit_depth) <= + desired_bits_per_mb || + low == worst_qindex); + return low; +} + int av1_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type, int qindex, double rate_target_ratio, aom_bit_depth_t bit_depth) { - int target_index = rc->worst_quality; - int i; - // Look up the current projected bits per block for the base index const int base_bits_per_mb = av1_rc_bits_per_mb(frame_type, qindex, 1.0, bit_depth); @@ -1691,14 +1757,9 @@ int av1_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type, // Find the target bits per mb based on the base value and given ratio. const int target_bits_per_mb = (int)(rate_target_ratio * base_bits_per_mb); - // Convert the q target to an index - for (i = rc->best_quality; i < rc->worst_quality; ++i) { - if (av1_rc_bits_per_mb(frame_type, i, 1.0, bit_depth) <= - target_bits_per_mb) { - target_index = i; - break; - } - } + const int target_index = + find_qindex_by_rate(target_bits_per_mb, bit_depth, frame_type, + rc->best_quality, rc->worst_quality); return target_index - qindex; } @@ -1720,7 +1781,7 @@ void av1_rc_set_gf_interval_range(const AV1_COMP *const cpi, oxcf->width, oxcf->height, cpi->framerate); if (rc->max_gf_interval == 0) rc->max_gf_interval = av1_rc_get_default_max_gf_interval( - cpi->framerate, rc->min_gf_interval, oxcf->gf_max_pyr_height); + cpi->framerate, rc->min_gf_interval); // Extended max interval for genuinely static scenes like slide shows. rc->static_scene_max_gf_interval = MAX_STATIC_GF_GROUP_LENGTH; diff --git a/third_party/aom/av1/encoder/ratectrl.h b/third_party/aom/av1/encoder/ratectrl.h index 36c738c8cc..1cd59940ce 100644 --- a/third_party/aom/av1/encoder/ratectrl.h +++ b/third_party/aom/av1/encoder/ratectrl.h @@ -15,6 +15,8 @@ #include "aom/aom_codec.h" #include "aom/aom_integer.h" +#include "aom_ports/mem.h" + #include "av1/common/blockd.h" #include "av1/common/onyxc_int.h" @@ -36,28 +38,27 @@ extern "C" { // Minimum and maximum height for the new pyramid structure. // (Old structure supports height = 1, but does NOT support height = 4). -#define MIN_PYRAMID_LVL 2 +#define MIN_PYRAMID_LVL 0 #define MAX_PYRAMID_LVL 4 #define MIN_GF_INTERVAL 4 #define MAX_GF_INTERVAL 16 #define FIXED_GF_INTERVAL 8 // Used in some testing modes only -static const double rate_factor_deltas[RATE_FACTOR_LEVELS] = { - 1.00, // INTER_NORMAL - 0.80, // INTER_LOW - 1.50, // INTER_HIGH - 1.25, // GF_ARF_LOW - 2.00, // GF_ARF_STD - 2.00, // KF_STD -}; - typedef struct { int resize_width; int resize_height; uint8_t superres_denom; } size_params_type; +enum { + INTER_NORMAL, + GF_ARF_LOW, + GF_ARF_STD, + KF_STD, + RATE_FACTOR_LEVELS +} UENUM1BYTE(RATE_FACTOR_LEVEL); + typedef struct { // Rate targetting variables int base_frame_target; // A baseline frame target before adjustment @@ -88,18 +89,9 @@ typedef struct { int source_alt_ref_pending; int source_alt_ref_active; int is_src_frame_alt_ref; + int is_src_frame_internal_arf; int sframe_due; - // Length of the bi-predictive frame group interval - int bipred_group_interval; - - // NOTE: Different types of frames may have different bits allocated - // accordingly, aiming to achieve the overall optimal RD performance. - int is_bwd_ref_frame; - int is_last_bipred_frame; - int is_bipred_frame; - int is_src_frame_ext_arf; - int avg_frame_bandwidth; // Average frame size target for clip int min_frame_bandwidth; // Minimum allocation used for any frame int max_frame_bandwidth; // Maximum burst rate allowed for a frame. @@ -147,8 +139,6 @@ typedef struct { int q_1_frame; int q_2_frame; - // Auto frame-scaling variables. - int rf_level_maxq[RATE_FACTOR_LEVELS]; float_t arf_boost_factor; // Q index used for ALT frame int arf_q; @@ -171,10 +161,7 @@ int av1_rc_get_default_min_gf_interval(int width, int height, double framerate); // Note av1_rc_get_default_max_gf_interval() requires the min_gf_interval to // be passed in to ensure that the max_gf_interval returned is at least as bis // as that. -int av1_rc_get_default_max_gf_interval(double framerate, int min_frame_rate, - int max_pyr_height); - -int av1_rc_get_fixed_gf_length(int max_pyr_height); +int av1_rc_get_default_max_gf_interval(double framerate, int min_gf_interval); // Generally at the high level, the following flow is expected // to be enforced for rate control: @@ -201,9 +188,11 @@ int av1_rc_get_fixed_gf_length(int max_pyr_height); // encode_frame_to_data_rate() function. struct EncodeFrameParams; void av1_rc_get_one_pass_vbr_params( - struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params); + struct AV1_COMP *cpi, uint8_t *const frame_update_type, + struct EncodeFrameParams *const frame_params, unsigned int frame_flags); void av1_rc_get_one_pass_cbr_params( - struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params); + struct AV1_COMP *cpi, uint8_t *const frame_update_type, + struct EncodeFrameParams *const frame_params, unsigned int frame_flags); // Post encode update of the rate control parameters based // on bytes used @@ -243,7 +232,14 @@ int av1_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex, int av1_rc_clamp_iframe_target_size(const struct AV1_COMP *const cpi, int target); int av1_rc_clamp_pframe_target_size(const struct AV1_COMP *const cpi, - int target); + int target, uint8_t frame_update_type); + +// Find q_index corresponding to desired_q, within [best_qindex, worst_qindex]. +// To be precise, 'q_index' is the smallest integer, for which the corresponding +// q >= desired_q. +// If no such q index is found, returns 'worst_qindex'. +int av1_find_qindex(double desired_q, aom_bit_depth_t bit_depth, + int best_qindex, int worst_qindex); // Computes a q delta (in "q index" terms) to get from a starting q value // to a target q value @@ -256,7 +252,7 @@ int av1_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type, int qindex, double rate_target_ratio, aom_bit_depth_t bit_depth); -int av1_frame_type_qdelta(const struct AV1_COMP *cpi, int rf_level, int q); +int av1_frame_type_qdelta(const struct AV1_COMP *cpi, int q); void av1_rc_update_framerate(struct AV1_COMP *cpi, int width, int height); @@ -267,8 +263,6 @@ void av1_set_target_rate(struct AV1_COMP *cpi, int width, int height); int av1_resize_one_pass_cbr(struct AV1_COMP *cpi); -void av1_estimate_qp_gop(struct AV1_COMP *cpi); - #ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/aom/av1/encoder/rd.c b/third_party/aom/av1/encoder/rd.c index f71ec8033b..d78e269e79 100644 --- a/third_party/aom/av1/encoder/rd.c +++ b/third_party/aom/av1/encoder/rd.c @@ -344,13 +344,7 @@ void av1_init_me_luts(void) { static const int rd_boost_factor[16] = { 64, 32, 32, 32, 24, 16, 12, 12, 8, 8, 4, 4, 2, 2, 1, 0 }; static const int rd_frame_type_factor[FRAME_UPDATE_TYPES] = { - 128, 144, 128, 128, 144, - // TODO(zoeliu): To adjust further following factor values. - 128, 128, 128, - // TODO(weitinglin): We should investigate if the values should be the same - // as the value used by OVERLAY frame - 144, // INTNL_OVERLAY_UPDATE - 128 // INTNL_ARF_UPDATE + 128, 144, 128, 128, 144, 144, 128 }; int av1_compute_rd_mult_based_on_qindex(const AV1_COMP *cpi, int qindex) { @@ -703,6 +697,7 @@ static double interp_cubic(const double *p, double x) { x * (3.0 * (p[1] - p[2]) + p[3] - p[0]))); } +/* static double interp_bicubic(const double *p, int p_stride, double x, double y) { double q[4]; @@ -712,623 +707,122 @@ static double interp_bicubic(const double *p, int p_stride, double x, q[3] = interp_cubic(p + 3 * p_stride, x); return interp_cubic(q, y); } +*/ -static const uint8_t bsize_model_cat_lookup[BLOCK_SIZES_ALL] = { +static const uint8_t bsize_curvfit_model_cat_lookup[BLOCK_SIZES_ALL] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 0, 0, 1, 1, 2, 2 }; -static int sse_norm_model_cat_lookup(double sse_norm) { +static int sse_norm_curvfit_model_cat_lookup(double sse_norm) { return (sse_norm > 16.0); } -static const double interp_rgrid_surf[4][33 * 18] = { +// Models distortion by sse using a logistic function on +// l = log2(sse / q^2) as: +// dbysse = 16 / (1 + k exp(l + c)) +static double get_dbysse_logistic(double l, double c, double k) { + const double A = 16.0; + const double dbysse = A / (1 + k * exp(l + c)); + return dbysse; +} + +// Models rate using a clamped linear function on +// l = log2(sse / q^2) as: +// rate = max(0, a + b * l) +static double get_rate_clamplinear(double l, double a, double b) { + const double rate = a + b * l; + return (rate < 0 ? 0 : rate); +} + +static const uint8_t bsize_surffit_model_cat_lookup[BLOCK_SIZES_ALL] = { + 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 0, 0, 2, 2, 4, 4 +}; + +static const double surffit_rate_params[9][4] = { { - 29.726102, 30.738006, 25.294088, 25.736759, 41.255961, - 41.937828, 41.937901, 42.110487, 46.038554, 46.593284, - 55.290144, 55.672257, 55.672289, 55.672284, 55.641633, - 54.251766, 38.404522, 36.186584, 30.977201, 32.031695, - 26.358675, 26.819956, 42.992269, 43.702888, 43.702966, - 43.882830, 47.992288, 48.920311, 57.633255, 58.015369, - 58.015396, 57.984745, 56.594876, 40.717227, 39.327227, - 37.709563, 30.977308, 32.041872, 26.587891, 26.801416, - 42.339251, 43.674340, 43.710377, 44.048333, 48.365747, - 57.251292, 57.999483, 58.015595, 57.984977, 56.595076, - 40.717426, 39.327559, 39.313319, 38.085580, 30.977328, - 32.271000, 31.802769, 26.377378, 27.473270, 43.021187, - 43.875643, 47.811034, 48.547182, 57.617338, 58.015563, - 58.001989, 56.982277, 40.734438, 39.327560, 39.313487, - 40.065111, 46.657660, 30.977329, 32.281067, 32.031899, - 26.358835, 26.820108, 42.992490, 43.882906, 47.992438, - 48.920477, 57.633450, 58.001989, 57.369478, 49.547092, - 39.714761, 39.313520, 40.065295, 48.834535, 51.525122, - 30.977329, 32.281072, 32.077511, 27.396520, 26.865699, - 42.992474, 43.882906, 48.358483, 57.251290, 57.985906, - 57.369511, 49.564105, 40.101962, 39.330532, 40.065297, - 48.835069, 57.817665, 145.394655, 30.977369, 32.281197, - 33.076074, 50.151877, 28.497451, 42.792931, 43.512994, - 48.377350, 57.604551, 57.386489, 49.951306, 40.118976, - 39.330567, 40.065298, 48.835069, 57.818203, 151.867755, - 153.625733, 31.447893, 32.750906, 32.266221, 32.302627, - 42.268290, 38.854272, 35.574619, 49.427510, 56.878041, - 50.330896, 48.931678, 39.717770, 40.065331, 48.835069, - 57.818191, 151.733328, 156.892368, 150.600520, 42.125514, - 43.448292, 33.901056, 49.284440, 47.710751, 52.761179, - 46.446220, 71.330907, 47.520016, 49.126258, 40.678046, - 40.107037, 48.835077, 57.818191, 151.733068, 153.820869, - 83.953859, 77.615621, 42.078145, 44.460837, 53.413056, - 53.860750, 51.935802, 60.688133, 54.022549, 59.058236, - 61.487243, 49.511225, 53.558701, 50.619860, 57.871196, - 151.733230, 153.821045, 83.819613, 77.759808, 76.318016, - 47.334708, 55.115021, 63.088351, 65.025437, 66.447005, - 66.685816, 72.840860, 70.204772, 75.247159, 75.769300, - 62.167236, 83.948064, 149.878947, 155.679346, 86.031186, - 83.012511, 86.265353, 124.454706, 64.496779, 78.702984, - 76.659370, 83.931191, 87.076287, 91.454837, 94.323380, - 104.708654, 109.932924, 118.596035, 126.154595, 114.409068, - 89.213630, 131.569970, 134.824613, 205.866155, 239.628810, - 233.070258, 72.308997, 94.104934, 101.404120, 121.159064, - 139.921349, 156.802796, 164.908506, 170.895200, 184.099064, - 198.250167, 207.100063, 207.922921, 207.455763, 210.915553, - 241.757520, 246.227265, 247.706317, 237.758893, 138.726610, - 135.459290, 198.494473, 240.094885, 275.356590, 295.461068, - 304.435273, 303.110796, 296.273053, 317.439936, 319.323966, - 331.200883, 330.246858, 256.379818, 247.994095, 247.767952, - 247.767210, 237.760453, 243.406633, 292.096487, 381.480937, - 421.494757, 458.357268, 483.808573, 487.800297, 481.212962, - 472.226349, 472.996935, 480.732289, 475.694812, 418.477476, - 412.710307, 268.338558, 261.989349, 261.987913, 251.406810, - 469.068582, 568.835648, 608.315967, 642.717253, 653.879813, - 681.008793, 688.659203, 677.706251, 668.348079, 652.995530, - 636.214467, 632.005555, 550.175654, 522.412011, 588.754096, - 591.721361, 591.719586, 567.821360, 667.228892, 787.133995, - 830.015474, 848.841400, 863.280871, 882.475988, 896.321308, - 889.205975, 878.059084, 871.467549, 860.073920, 814.054753, - 726.521001, 747.583633, 751.922326, 752.065525, 752.062970, - 721.688835, 795.516527, 916.651129, 1045.662316, 1064.160855, - 1070.930169, 1060.177543, 1080.056283, 1096.204211, 1095.337870, - 1098.401980, 1087.336698, 1022.507849, 916.586633, 938.424837, - 942.750167, 945.352203, 945.457385, 907.272493, 943.653980, - 1021.248655, 1129.544563, 1267.035138, 1281.163505, 1235.783117, - 1258.747831, 1285.425350, 1293.324247, 1314.802791, 1320.786990, - 1253.910457, 1138.645930, 1091.248129, 1161.397763, 1220.617170, - 1223.081462, 1173.684183, 1077.194216, 1216.741493, 1278.148407, - 1383.489545, 1497.622061, 1505.771495, 1422.262568, 1462.870558, - 1491.544736, 1494.922359, 1533.495237, 1509.573542, 1356.235452, - 1322.878872, 1324.869188, 1327.897500, 1337.708123, 1284.090364, - 1177.946473, 1335.104679, 1414.612819, 1508.772208, 1656.204257, - 1636.726625, 1693.515385, 1658.176544, 1626.718453, 1699.881842, - 1721.127481, 1715.540667, 1610.027798, 1528.475428, 1525.090509, - 1534.987574, 1760.238672, 1698.643936, 1285.821939, 1417.714456, - 1527.788112, 1660.663143, 1648.660011, 1838.036905, 1838.669356, - 1803.685279, 1895.404145, 1878.456820, 1907.761437, 1891.806178, - 1798.474576, 1772.695413, 1777.922135, 1782.961020, 1891.441373, - 1819.624352, 1363.652278, 1525.975687, 1664.733346, 1725.645678, - 1842.181220, 1845.935374, 1847.645643, 2084.649919, 2156.327082, - 2070.132265, 2093.920913, 2066.856209, 1935.233655, 1757.519179, - 1894.998543, 1904.433642, 1909.668939, 1832.757449, 1466.924321, - 1622.799826, 1723.952077, 1846.075992, 1857.802996, 1849.640165, - 2127.098845, 2370.422248, 2375.277013, 2471.317955, 2282.670767, - 2242.894713, 2110.737592, 1924.405669, 2022.847422, 2092.614827, - 2113.100659, 2028.502155, 1561.024406, 1719.325091, 1845.872940, - 1857.825889, 1850.155079, 2127.184115, 2372.221523, 2397.560183, - 2793.802030, 2525.955468, 2512.515727, 2465.117634, 2335.991284, - 2104.381407, 2124.161214, 2128.328755, 2129.221941, 2043.260174, - 1651.007418, 1782.604815, 1855.046326, 1850.154844, 2127.184127, - 2372.221529, 2397.560385, 2794.384764, 2544.781302, 2651.443272, - 2739.000803, 2702.474497, 2522.919941, 2276.563499, 2274.919319, - 2275.308573, 2275.300889, 2183.406597, 1713.105119, 1852.260885, - 1850.032717, 2127.168115, 2371.857312, 2397.544382, 2794.384763, - 2544.781370, 2651.673334, 2746.255820, 2763.494638, 2872.508140, - 2846.367495, 2305.137739, 2281.712444, 2281.725436, 2281.717621, - 2189.564169, 1780.286046, 1850.026376, 2127.168073, 2371.493095, - 2389.254845, 2794.020546, 2544.781339, 2651.673334, 2746.255845, - 2763.564597, 2874.688737, 2884.399707, 2860.263639, 2306.077266, - 2281.728045, 2281.725981, 2281.718165, 2189.564691, 1775.067091, - 2127.161715, 2371.493094, 2389.238842, 2793.656329, 2544.765337, - 2651.673332, 2746.255845, 2763.564597, 2874.688743, 2884.401957, - 2884.614099, 2860.264919, 2306.079244, 2281.728130, 2281.725981, - 2281.718165, 2189.564691, 2052.948444, 2371.486799, 2389.238842, - 2793.656328, 2544.765306, 2651.673331, 2746.255845, 2763.564597, - 2874.688743, 2884.401957, 2884.616164, 2884.614218, 2861.248329, - 2328.461556, 2282.711540, 2281.726065, 2281.718165, 2189.564691, - 2285.514142, 2389.231550, 2793.656328, 2544.765306, 2651.673331, - 2746.255845, 2763.564597, 2874.688743, 2884.401957, 2884.616164, - 2884.616200, 2884.616117, 2883.630641, 2837.880625, 2305.093852, - 2281.727963, 2281.718165, 2189.564691, 2293.011609, 2793.639080, - 2544.755886, 2651.663879, 2746.245982, 2763.554715, 2874.678861, - 2884.392075, 2884.606282, 2884.606318, 2884.606318, 2884.606318, - 2884.604170, 2860.253139, 2306.069362, 2281.720230, 2281.710349, - 2189.557190, 2600.476153, 2437.607663, 2540.606072, 2634.813199, - 2647.265343, 2758.176106, 2767.889302, 2768.103509, 2768.103545, - 2768.103545, 2768.103545, 2768.103545, 2768.101564, 2744.735758, - 2212.932478, 2189.566673, 2189.557190, 2101.125891, + 638.390212, + 2.253108, + 166.585650, + -3.939401, }, { - 8.370360, 8.509764, 8.942497, 8.962541, 8.993650, - 9.401615, 9.414854, 9.308823, 9.304164, 9.304163, - 9.304164, 9.304609, 9.324803, 9.555049, 9.565277, - 9.571194, 9.647370, 9.451428, 8.722648, 8.867100, - 9.300225, 9.352116, 9.672213, 9.809754, 9.794381, - 9.699874, 9.695753, 9.695753, 9.696199, 9.716392, - 9.947083, 9.967407, 9.973767, 10.050124, 10.454503, - 14.384681, 8.722677, 8.848489, 8.875968, 9.334087, - 9.685450, 9.793645, 9.413799, 9.683184, 9.695785, - 9.696231, 9.716425, 9.947116, 9.967440, 9.973802, - 10.050158, 10.454591, 15.023561, 15.153937, 8.723107, - 8.857467, 8.857756, 9.333268, 9.685451, 9.792911, - 9.397076, 9.682449, 9.695786, 9.706329, 9.946672, - 9.967440, 9.973802, 10.050158, 10.454591, 15.023647, - 16.163497, 23.616388, 8.732904, 9.080445, 8.867552, - 9.333269, 9.685451, 9.792910, 9.397075, 9.682449, - 9.696231, 9.716869, 9.957343, 9.973801, 10.050158, - 10.454591, 15.023647, 16.163589, 24.700350, 25.680478, - 8.733342, 9.090251, 8.868006, 9.333704, 9.685477, - 9.792913, 9.397086, 9.682895, 9.716424, 9.947246, - 9.973357, 10.050158, 10.454591, 15.023647, 16.163589, - 24.700554, 28.087109, 55.858717, 8.827122, 9.186580, - 8.932093, 9.387586, 9.780396, 9.827339, 9.522726, - 9.715771, 9.936594, 9.972878, 10.050158, 10.454591, - 15.023647, 16.163589, 24.700554, 28.087318, 58.323463, - 58.504090, 11.020305, 11.418729, 10.432068, 10.462985, - 11.980204, 10.705178, 12.392570, 10.364495, 9.829351, - 10.102947, 10.457228, 15.023647, 16.163589, 24.700554, - 28.087319, 58.323704, 60.984846, 58.926665, 12.554530, - 12.511580, 11.828923, 12.308025, 13.298760, 13.044522, - 12.945689, 13.556029, 12.673484, 12.067338, 15.194674, - 16.168241, 24.700556, 28.087321, 58.339708, 61.349323, - 61.787659, 67.232638, 15.008518, 15.485683, 15.872869, - 16.107583, 15.835820, 16.877645, 17.678106, 18.822352, - 20.208378, 19.665073, 19.090588, 25.203257, 28.104179, - 58.339741, 61.713565, 70.078019, 70.458033, 67.961299, - 17.761908, 35.462897, 20.615440, 19.929266, 20.679593, - 22.692816, 25.941528, 29.215386, 34.956494, 38.908872, - 35.866805, 37.824252, 59.112479, 61.729892, 70.173287, - 72.702736, 72.797652, 69.857555, 20.506234, 39.710259, - 24.054829, 25.703729, 31.621917, 38.509103, 44.229053, - 56.544042, 67.468427, 79.581678, 80.144809, 78.556111, - 74.399792, 73.852202, 76.027762, 117.654284, 119.482115, - 114.656650, 25.548773, 48.434418, 42.617322, 59.026359, - 82.885084, 103.416136, 110.596012, 118.893312, 139.741780, - 150.511338, 161.901080, 167.647532, 162.429576, 152.184833, - 152.445359, 168.398896, 169.099625, 162.269514, 82.673806, - 70.110218, 132.312464, 183.332020, 215.910819, 237.790158, - 239.207817, 229.469490, 230.174506, 250.717349, 253.902836, - 250.549622, 207.721430, 175.337781, 174.022082, 174.844559, - 179.095719, 164.620978, 109.303621, 158.273825, 282.689646, - 346.940666, 386.914531, 410.989383, 397.460378, 370.331321, - 364.107004, 366.410030, 380.333542, 363.501310, 294.254304, - 262.048447, 260.790777, 265.975674, 362.177173, 183.336338, - 404.520239, 473.542827, 507.606249, 529.861510, 559.718099, - 588.632991, 577.691379, 533.799138, 522.780262, 528.340923, - 525.905829, 507.879853, 415.994095, 425.708669, 426.932731, - 441.248848, 446.721366, 435.160437, 604.741350, 709.039378, - 780.416591, 732.829427, 733.032326, 766.737728, 758.413295, - 720.856125, 705.746779, 717.211527, 703.753940, 661.340782, - 552.231698, 523.727433, 522.707356, 523.327476, 523.380946, - 502.845082, 745.431184, 827.490462, 962.723712, 998.756854, - 911.671845, 907.248783, 925.966430, 901.879365, 900.337680, - 919.439892, 914.334537, 842.878262, 704.639674, 702.883177, - 703.067185, 703.067254, 703.064850, 674.669690, 894.169844, - 1025.903412, 1134.439771, 1219.193918, 1158.526825, 1079.781195, - 1077.325043, 1076.106019, 1075.934290, 1117.511500, 1135.469693, - 1063.699731, 901.900714, 920.553711, 921.681648, 921.681860, - 921.679125, 884.454592, 994.327035, 1175.512444, 1231.834682, - 1307.830164, 1407.421778, 1326.963114, 1253.371428, 1250.787362, - 1269.653825, 1282.857814, 1343.429863, 1307.501250, 1114.048857, - 983.551449, 978.228429, 979.601009, 984.578211, 945.021162, - 1135.950879, 1278.106415, 1310.418579, 1419.457570, 1488.462247, - 1521.009066, 1542.754625, 1434.182316, 1454.788272, 1471.133321, - 1506.092266, 1521.256433, 1327.843116, 1309.574134, 1310.302024, - 1341.725430, 1459.021892, 1404.992306, 1232.172010, 1349.471091, - 1428.291402, 1487.206606, 1535.398237, 1746.731849, 1716.656287, - 1635.940921, 1639.303784, 1673.047286, 1693.682270, 1671.177816, - 1517.793233, 1479.700025, 1478.369392, 1483.694229, 1578.610159, - 1518.853600, 1297.751330, 1428.849626, 1485.708645, 1493.412575, - 1741.940596, 1728.475751, 1735.779511, 1858.578642, 1918.863689, - 1863.724239, 1891.004802, 1842.815568, 1675.715043, 1588.071911, - 1589.814363, 1592.306606, 1596.345158, 1532.039001, 1373.297412, - 1461.343441, 1492.261194, 1736.797392, 1653.192795, 1733.476694, - 1888.263820, 2082.789610, 1991.468137, 1883.805569, 2116.637406, - 2071.956368, 1871.698996, 1644.776129, 1756.448731, 1809.269770, - 1811.354640, 1738.198277, 1403.551810, 1491.185946, 1736.750346, - 1653.047461, 1730.172539, 1888.230584, 2085.624280, 1993.438043, - 1786.471183, 2337.838134, 2448.464613, 2336.935884, 2097.581279, - 1808.183187, 1828.142934, 1821.170551, 1820.795051, 1747.257197, - 1427.896429, 1736.558511, 1653.047441, 1730.172527, 1888.230448, - 2087.322730, 2032.094869, 1787.954651, 2341.066895, 2641.531977, - 2539.340235, 2507.302262, 2309.116599, 2030.685235, 2078.550644, - 1842.720183, 1832.216691, 1758.216718, 1580.198506, 1648.792285, - 1730.172167, 1888.230448, 2087.322736, 2032.169494, 1789.653110, - 2341.141530, 2641.873005, 2555.239313, 2709.221434, 2715.218691, - 2682.937371, 2124.893499, 2102.967545, 2092.601766, 2092.133383, - 2007.636776, 1578.033231, 1729.979789, 1888.230432, 2087.322736, - 2032.169494, 1789.653117, 2341.141675, 2641.873012, 2555.239371, - 2709.566764, 2723.749115, 2724.064349, 2699.003101, 2128.626010, - 2103.563660, 2103.560569, 2103.553324, 2018.595528, 1663.710423, - 1888.224796, 2087.322736, 2032.169494, 1789.653117, 2341.141675, - 2641.873012, 2555.239371, 2709.566764, 2723.749145, 2724.067198, - 2724.065212, 2700.016608, 2151.662616, 2104.575854, 2103.561585, - 2103.554293, 2018.596458, 1818.473656, 2087.316820, 2032.169494, - 1789.653117, 2341.141675, 2641.873012, 2555.239371, 2709.566764, - 2723.749145, 2724.067198, 2724.067252, 2724.067166, 2723.052897, - 2675.966135, 2127.612143, 2103.563538, 2103.554293, 2018.596458, - 2011.142209, 2032.163033, 1789.653117, 2341.141675, 2641.873012, - 2555.239371, 2709.566764, 2723.749145, 2724.067198, 2724.067252, - 2724.067252, 2724.067252, 2724.065041, 2699.002510, 2128.626241, - 2103.563710, 2103.554293, 2018.596458, 1947.414707, 1789.636821, - 2341.132961, 2641.863707, 2555.230039, 2709.557432, 2723.739813, - 2724.057867, 2724.057920, 2724.057920, 2724.057920, 2724.057920, - 2724.055881, 2700.007276, 2151.653370, 2104.568562, 2103.547173, - 2018.589543, 1614.950117, 2233.740132, 2539.133260, 2445.528333, - 2599.538876, 2613.721229, 2614.039283, 2614.039337, 2614.039337, - 2614.039337, 2614.039337, 2614.039337, 2614.039251, 2613.025067, - 2566.950536, 2041.634786, 2018.591496, 1937.063243, + 5.256905, + 81.997240, + -1.321771, + 17.694216, }, { - 2.147514, 2.237898, 2.237803, 2.237151, 2.275320, - 2.279324, 2.332179, 2.334501, 2.322470, 2.048664, - 2.036634, 2.036633, 2.043731, 2.205267, 2.213955, - 2.286115, 3.114672, 3.150236, 2.237900, 2.332085, - 2.329658, 2.278309, 2.368754, 2.375255, 2.430335, - 2.432248, 2.408693, 2.134381, 2.122351, 2.122650, - 2.136546, 2.299971, 2.379228, 3.209393, 3.546162, - 6.294600, 2.271800, 2.333582, 2.329564, 2.275984, - 2.368873, 2.380129, 2.430556, 2.420732, 2.146419, - 2.122864, 2.122657, 2.136254, 2.293180, 2.378937, - 3.209400, 3.546195, 6.591552, 7.028860, 3.043184, - 2.367477, 2.329567, 2.275984, 2.373739, 2.490860, - 2.435421, 2.420225, 2.134895, 2.122658, 2.136254, - 2.293180, 2.378936, 3.209400, 3.546195, 6.591617, - 7.795421, 17.743823, 3.078566, 2.402859, 2.331056, - 2.275985, 2.373953, 2.495725, 2.435129, 2.408702, - 2.134688, 2.136255, 2.293180, 2.378936, 3.209400, - 3.546195, 6.591617, 7.795492, 18.578087, 19.754344, - 3.112459, 3.174471, 2.370323, 2.279235, 2.375398, - 2.494530, 2.423939, 2.146738, 2.136763, 2.293180, - 2.378939, 3.209400, 3.546195, 6.591617, 7.795492, - 18.578249, 21.659892, 44.204400, 3.089303, 3.189642, - 2.509317, 2.372448, 2.432176, 2.489915, 2.461894, - 2.170933, 2.301935, 2.380378, 3.234280, 3.547288, - 6.591617, 7.795492, 18.578249, 21.660057, 46.157016, - 46.346972, 2.545327, 2.662725, 2.893299, 2.840660, - 3.006570, 3.048065, 3.224317, 2.907751, 2.627415, - 3.268959, 4.113541, 6.616496, 7.795494, 18.578249, - 21.660057, 46.157182, 48.299592, 46.394222, 2.942757, - 3.155386, 3.688593, 3.481851, 3.715109, 4.145502, - 4.681446, 5.080585, 4.600294, 4.278096, 6.726591, - 7.800142, 18.578250, 21.660057, 46.157182, 48.299758, - 48.346843, 46.394230, 3.793838, 5.473983, 4.608110, - 4.665834, 4.593326, 5.621563, 7.102711, 9.025169, - 10.122234, 10.159723, 10.023976, 18.857332, 21.668316, - 46.157261, 48.299839, 48.347091, 48.346956, 46.394491, - 4.271176, 6.466779, 5.484235, 6.027476, 7.301091, - 9.352794, 12.715546, 16.192475, 22.560070, 27.958500, - 27.052873, 26.766614, 46.406220, 49.221059, 49.307058, - 49.315280, 49.587875, 49.469333, 4.312908, 7.475387, - 7.833860, 10.223714, 16.775457, 24.234924, 32.175390, - 45.584094, 54.342692, 64.941124, 66.654416, 62.626466, - 52.266425, 72.572219, 73.485826, 73.672773, 79.880600, - 119.538616, 9.063034, 10.103318, 19.539238, 36.472083, - 62.703355, 82.709235, 91.988082, 100.285999, 115.687111, - 124.329614, 125.634719, 122.315209, 112.379054, 130.322056, - 131.130875, 131.139174, 131.411947, 127.988734, 19.796341, - 25.882925, 93.253237, 153.548489, 189.401787, 213.347763, - 206.988813, 189.758327, 189.286642, 204.628607, 202.531100, - 201.472079, 186.352604, 214.273591, 215.531911, 215.769339, - 221.170008, 212.465343, 169.309448, 175.824536, 224.720662, - 303.438505, 343.063029, 370.535703, 343.624360, 300.549614, - 289.296503, 298.082336, 310.854450, 294.466802, 270.163254, - 249.832086, 248.983097, 254.384429, 377.318513, 367.262701, - 353.359003, 463.883442, 447.419222, 453.002989, 489.006379, - 528.921013, 500.655371, 439.860852, 423.703334, 423.144668, - 431.190760, 422.628418, 346.619232, 383.306337, 385.067653, - 385.305123, 390.705188, 375.153218, 539.087109, 664.575466, - 708.656277, 662.482491, 618.723324, 674.195070, 656.531281, - 596.084694, 576.463478, 584.628279, 577.147684, 562.515800, - 453.416064, 428.149599, 427.247359, 427.247313, 427.246307, - 409.990807, 687.292802, 777.058828, 905.030245, 912.381642, - 788.119446, 769.561998, 795.174180, 761.722895, 738.637994, - 753.718308, 761.364923, 712.753474, 603.465105, 591.662313, - 594.079856, 594.200005, 594.197958, 570.199152, 779.060173, - 951.796204, 1069.175314, 1170.755086, 1067.610429, 949.009502, - 934.793193, 914.719926, 899.055222, 929.548018, 948.443491, - 883.741844, 754.604267, 719.256051, 780.076337, 782.811403, - 782.547500, 745.230787, 922.165691, 1108.252645, 1185.274121, - 1237.276156, 1266.012843, 1226.812751, 1102.465568, 1085.286013, - 1075.433883, 1091.747391, 1130.914031, 1079.716598, 927.463157, - 942.209973, 945.879069, 946.263934, 946.332394, 778.375752, - 1069.516638, 1181.232895, 1244.763295, 1280.392765, 1419.980489, - 1443.722749, 1374.005679, 1247.118477, 1252.786860, 1265.078694, - 1280.267151, 1273.804486, 1085.050290, 1037.883124, 1036.171983, - 1042.457032, 1185.241611, 1137.692305, 1136.326843, 1246.301355, - 1321.499026, 1422.581245, 1459.231744, 1574.624247, 1593.556714, - 1554.290382, 1474.539686, 1480.100956, 1464.679108, 1412.507057, - 1251.278472, 1197.245685, 1195.175062, 1201.168704, 1337.571298, - 1289.300549, 1198.629451, 1322.569335, 1424.892277, 1470.063106, - 1576.317080, 1629.881049, 1759.007438, 1685.455960, 1823.183401, - 1696.763728, 1720.897219, 1582.701816, 1409.816846, 1352.692221, - 1350.761108, 1356.950874, 1362.935844, 1308.131482, 1273.245632, - 1447.544983, 1471.079493, 1576.789596, 1629.891022, 1759.113129, - 1704.167080, 2077.760859, 1944.393655, 2008.282739, 1951.682502, - 1905.896173, 1653.621076, 1524.210363, 1526.775296, 1662.009621, - 1667.942643, 1600.578688, 1394.223453, 1472.070445, 1576.833336, - 1629.890970, 1757.978972, 1678.353822, 2077.085726, 1963.548056, - 2214.617152, 2129.636312, 2170.262437, 2204.652056, 1892.295487, - 1652.520236, 1673.779173, 1681.078895, 1681.334159, 1613.428869, - 1413.634564, 1576.837954, 1629.890974, 1757.978960, 1678.303800, - 2075.951574, 1963.498706, 2214.984962, 2140.104142, 2224.748512, - 2358.489855, 2338.333779, 2147.326062, 1959.161343, 1704.142189, - 1693.264072, 1693.257371, 1624.870507, 1522.455341, 1630.102341, - 1757.978970, 1678.205343, 2073.710713, 1963.613482, 2219.840292, - 2140.317509, 2224.830630, 2367.413225, 2514.706448, 2519.715697, - 2490.578281, 1997.672226, 1965.092163, 1964.608831, 1964.602061, - 1885.256194, 1566.312385, 1757.983049, 1678.205154, 2071.469838, - 1912.611809, 2222.454760, 2250.824415, 2229.685973, 2367.413669, - 2515.007972, 2527.205354, 2527.466626, 2505.215096, 1998.786468, - 1976.532889, 1976.530885, 1976.524114, 1896.696743, 1692.302152, - 1678.199584, 2071.469829, 1912.513351, 2220.213903, 2250.939287, - 2234.541308, 2367.626998, 2515.007990, 2527.205379, 2527.469148, - 2527.467382, 2506.115004, 2019.240121, 1977.432526, 1976.531972, - 1976.525125, 1896.697713, 1606.783592, 2071.463772, 1912.513351, - 2220.213894, 2250.939097, 2234.541317, 2367.627410, 2515.008008, - 2527.205379, 2527.469148, 2527.469193, 2527.469116, 2526.568562, - 2484.760968, 1997.886085, 1976.533707, 1976.525125, 1896.697713, - 2004.589287, 1912.507679, 2220.213894, 2250.939097, 2234.541317, - 2367.627410, 2515.008008, 2527.205379, 2527.469148, 2527.469193, - 2527.469193, 2527.469193, 2527.467229, 2505.214602, 1998.786486, - 1976.533860, 1976.525125, 1896.697713, 1827.779426, 2220.199076, - 2250.930988, 2234.532682, 2367.618752, 2514.999350, 2527.196721, - 2527.460490, 2527.460534, 2527.460534, 2527.460534, 2527.460534, - 2527.458723, 2506.106346, 2019.231539, 1977.425679, 1976.518431, - 1896.691216, 2056.541124, 2160.944440, 2138.934044, 2265.803052, - 2412.920916, 2425.118264, 2425.382033, 2425.382078, 2425.382078, - 2425.382078, 2425.382078, 2425.382078, 2425.382002, 2424.481524, - 2383.572672, 1917.153083, 1896.692951, 1820.088116, + -74.193045, + 72.431868, + -19.033152, + 15.407276, }, { - 0.254129, 0.265575, 0.267769, 0.316933, 0.320396, - 0.350337, 0.358368, 0.358663, 0.358663, 0.358675, - 0.359199, 0.365181, 0.366036, 0.392895, 0.701286, - 0.812014, 1.926722, 2.011743, 0.247749, 0.276002, - 0.279039, 0.330191, 0.332015, 0.365000, 0.373450, - 0.373758, 0.373759, 0.374032, 0.380276, 0.381405, - 0.408276, 0.717257, 0.841415, 1.958868, 2.298681, - 4.856667, 0.246998, 0.275970, 0.279040, 0.328326, - 0.289563, 0.363136, 0.373451, 0.373760, 0.373771, - 0.374308, 0.381144, 0.408277, 0.717258, 0.841416, - 1.958870, 2.298703, 5.088461, 5.484975, 0.246965, - 0.275218, 0.279007, 0.328244, 0.287698, 0.363054, - 0.373451, 0.373771, 0.374296, 0.380881, 0.408266, - 0.717258, 0.841416, 1.958870, 2.298703, 5.088514, - 6.102534, 14.287379, 0.246213, 0.258111, 0.278255, - 0.328244, 0.287698, 0.363054, 0.373452, 0.374034, - 0.380870, 0.408644, 0.725849, 0.841794, 1.958870, - 2.298703, 5.088514, 6.102591, 14.959455, 15.913957, - 0.246180, 0.257402, 0.279186, 0.328526, 0.290138, - 0.364877, 0.376133, 0.375014, 0.408382, 0.734439, - 1.037308, 1.967461, 2.298704, 5.088514, 6.102591, - 14.959584, 17.441072, 35.429097, 0.250019, 0.262303, - 0.303891, 0.340011, 0.350106, 0.413735, 0.446832, - 0.410301, 0.734390, 1.038841, 2.002354, 2.300237, - 5.088514, 6.102591, 14.959584, 17.441204, 36.992539, - 37.110962, 0.339750, 0.354696, 0.373261, 0.461008, - 0.462495, 0.598987, 0.695421, 0.760530, 1.068705, - 2.029958, 2.898902, 5.114817, 6.102593, 14.959584, - 17.441205, 36.992675, 38.648954, 36.568097, 0.400795, - 0.421342, 0.508307, 0.588014, 0.677109, 0.972744, - 1.364551, 2.005727, 2.968255, 3.091537, 5.221096, - 6.106993, 14.959585, 17.441202, 36.995441, 38.712050, - 38.170575, 37.947398, 0.489106, 0.499732, 0.682198, - 0.797985, 0.928841, 1.529889, 3.407135, 6.047262, - 9.020716, 9.566838, 8.225222, 15.250390, 17.449015, - 36.967227, 38.773771, 39.603706, 39.612863, 38.072105, - 0.782539, 0.400752, 1.185871, 1.379942, 2.131362, - 4.169824, 9.556239, 12.949414, 21.418888, 24.451152, - 23.409241, 22.939144, 37.166430, 38.131684, 39.591435, - 39.985395, 39.999803, 38.384307, 1.616514, 0.576268, - 3.109295, 3.930083, 8.248113, 15.543679, 28.108995, - 37.139521, 46.111565, 52.306471, 54.245700, 51.814241, - 40.882242, 41.810659, 42.231519, 48.976557, 49.261637, - 47.271630, 5.094715, 1.500966, 10.566421, 19.002838, - 38.783971, 59.976285, 70.642488, 79.940911, 88.863960, - 91.805239, 95.624856, 92.381504, 94.587340, 93.842585, - 93.403266, 93.670318, 93.432487, 89.648397, 0.664794, - 7.849196, 61.154449, 96.443290, 137.609372, 162.556446, - 148.037064, 138.292519, 136.715840, 145.772994, 149.246615, - 151.612049, 131.470885, 109.201663, 101.316335, 101.904288, - 101.932270, 97.814994, 6.925953, 50.062367, 155.094765, - 216.414869, 252.438993, 271.718839, 232.337598, 204.289605, - 199.194140, 205.331210, 215.677297, 214.590331, 188.109722, - 172.081271, 228.048207, 250.892300, 251.787562, 241.618501, - 134.674271, 296.106246, 298.718911, 312.356451, 323.413855, - 342.631007, 307.749299, 283.067516, 265.987870, 265.460375, - 276.156298, 267.602576, 244.127989, 255.341106, 257.373708, - 258.333723, 258.372207, 247.937137, 342.349647, 510.603738, - 581.005531, 478.386434, 373.143790, 378.600404, 377.561939, - 356.141074, 338.631477, 331.842551, 340.566852, 327.567230, - 297.260507, 287.191935, 263.781497, 262.767950, 262.766967, - 252.154399, 475.742336, 629.567678, 578.444958, 564.378757, - 438.113186, 396.420987, 414.959234, 431.302969, 421.606208, - 403.786618, 405.430259, 389.856615, 363.613524, 366.303795, - 365.460005, 365.415394, 365.414130, 350.655776, 624.537781, - 642.232055, 604.750655, 630.663539, 588.111844, 475.625654, - 468.814426, 477.664040, 494.124835, 483.676981, 477.873259, - 452.815795, 423.548326, 431.959314, 432.336669, 431.259561, - 431.158392, 412.599201, 599.136090, 596.383540, 649.766837, - 714.641904, 647.024168, 546.886099, 544.047374, 542.897551, - 558.506982, 555.978025, 571.819113, 532.351774, 510.677525, - 495.125872, 493.402635, 468.981876, 468.871284, 423.950331, - 572.225475, 705.639818, 1024.735591, 667.143308, 595.280675, - 762.720257, 552.209148, 613.853858, 630.029121, 653.039002, - 643.569732, 623.030443, 573.888949, 571.441956, 571.380435, - 572.467453, 621.621663, 597.446835, 681.815611, 1037.097688, - 905.438670, 599.972561, 762.219180, 517.929098, 688.053947, - 744.181205, 679.524546, 682.569374, 713.780286, 707.985178, - 646.983619, 636.062414, 635.699032, 635.794133, 637.956277, - 612.281811, 1009.018046, 905.871087, 604.028246, 629.564692, - 511.991374, 689.885845, 836.027416, 766.534552, 881.860194, - 735.849782, 783.725360, 809.653496, 750.636979, 811.765460, - 814.639525, 816.244480, 818.253804, 785.288396, 867.862571, - 604.231326, 629.308626, 506.143862, 689.628928, 836.193031, - 774.742632, 1007.244245, 1293.627165, 897.984304, 931.611215, - 973.236387, 945.068518, 947.276414, 950.892263, 987.500595, - 1033.288662, 993.423200, 674.214249, 634.009759, 506.144239, - 689.628432, 836.193010, 774.742663, 1007.434892, 1306.991055, - 1109.422389, 1067.304686, 1126.861498, 1124.180515, 989.502672, - 997.732672, 1042.608506, 1046.158446, 1048.166963, 1005.915872, - 633.151925, 507.355996, 689.628570, 836.193810, 774.742698, - 1007.434892, 1306.991101, 1109.775470, 1079.300073, 1239.065289, - 1628.963638, 1322.149598, 1152.072478, 1133.642807, 1135.074392, - 1135.159950, 1135.156239, 1089.309834, 1002.301724, 712.557708, - 836.610527, 784.181750, 1007.849615, 1306.991136, 1109.775470, - 1079.300117, 1239.231971, 1644.540785, 1609.385289, 1575.587962, - 1175.113940, 1139.762609, 1138.978460, 1138.978401, 1138.974499, - 1092.973876, 693.249751, 850.650934, 794.193638, 1222.681498, - 1316.430188, 1109.776271, 1079.300117, 1239.231971, 1644.540839, - 1609.866572, 1604.515037, 1603.618487, 1568.302641, 1157.017568, - 1138.980254, 1138.978724, 1138.974823, 1092.974187, 834.755585, - 1090.883669, 1236.131974, 1325.870346, 1110.190994, 1079.300152, - 1239.231971, 1644.540839, 1609.866572, 1604.515142, 1604.380213, - 1604.378532, 1585.580675, 1157.776710, 1138.980319, 1138.978724, - 1138.974823, 1092.974187, 1056.722338, 1249.164781, 1326.443132, - 1110.191843, 1079.300187, 1239.231971, 1644.540839, 1609.866572, - 1604.515142, 1604.380213, 1604.380190, 1604.378596, 1585.582205, - 1157.778240, 1138.980383, 1138.978724, 1138.974823, 1092.974187, - 1204.957557, 1326.440488, 1110.191892, 1079.300187, 1239.231971, - 1644.540839, 1609.866572, 1604.515142, 1604.380213, 1604.380190, - 1604.380190, 1604.378661, 1586.341349, 1175.056279, 1139.739527, - 1138.978789, 1138.974823, 1092.974187, 1275.872102, 1110.183396, - 1079.294485, 1239.226464, 1644.535343, 1609.861076, 1604.509646, - 1604.374717, 1604.374695, 1604.374695, 1604.374695, 1604.374630, - 1603.613892, 1568.297204, 1157.013600, 1138.976353, 1138.970921, - 1092.970443, 1014.576161, 1029.697894, 1172.002606, 1579.603765, - 1545.063972, 1539.712554, 1539.577625, 1539.577603, 1539.577603, - 1539.577603, 1539.577603, 1539.577603, 1539.576008, 1521.537360, - 1111.012900, 1092.975717, 1092.970443, 1048.827820, + 416.770113, + 14.794188, + 167.686830, + -6.997756, + }, + { + 378.511276, + 9.558376, + 154.658843, + -6.635663, + }, + { + 277.818787, + 4.413180, + 150.317637, + -9.893038, + }, + { + 142.212132, + 11.542038, + 94.393964, + -5.518517, + }, + { + 219.100256, + 4.007421, + 108.932852, + -6.981310, + }, + { + 222.261971, + 3.251049, + 95.972916, + -5.609789, }, }; -static const double interp_dgrid_surf[33 * 18] = { - 15.491252, 15.496413, 15.496379, 15.394447, 15.394431, 15.446941, 15.480480, - 15.480491, 15.480491, 15.480491, 15.480573, 15.603112, 15.603153, 15.602880, - 15.196621, 15.195983, 14.447585, 14.442076, 15.599420, 15.501644, 15.501575, - 15.399610, 15.399669, 15.452121, 15.485671, 15.485682, 15.485682, 15.485724, - 15.608303, 15.608385, 15.608113, 15.201854, 15.201079, 14.452681, 14.451350, - 13.210484, 15.599455, 15.501644, 15.501575, 15.399686, 15.626744, 15.452197, - 15.485671, 15.485682, 15.485682, 15.485765, 15.608344, 15.608113, 15.201854, - 15.201079, 14.452681, 14.451350, 13.214913, 13.208705, 15.599455, 15.501679, - 15.501575, 15.399686, 15.626820, 15.452197, 15.485671, 15.485682, 15.485765, - 15.608303, 15.608113, 15.201854, 15.201079, 14.452681, 14.451350, 13.214913, - 13.212184, 10.377543, 15.599489, 15.604652, 15.501610, 15.399686, 15.626820, - 15.452197, 15.485671, 15.485724, 15.608303, 15.608113, 15.201794, 15.201079, - 14.452681, 14.451350, 13.214913, 13.212184, 10.381022, 10.373758, 15.599489, - 15.604686, 15.501645, 15.399727, 15.626807, 15.452213, 15.485673, 15.485765, - 15.608072, 15.201734, 15.022022, 14.452621, 14.451350, 13.214913, 13.212184, - 10.381022, 10.375351, 4.752366, 15.599553, 15.604785, 15.606745, 15.523109, - 15.588440, 15.498592, 15.490939, 15.608113, 15.201734, 15.022022, 14.452398, - 14.451350, 13.214913, 13.212184, 10.381022, 10.375351, 4.753958, 4.748594, - 15.788491, 15.793763, 15.727178, 15.593404, 15.576185, 15.541155, 15.528638, - 15.443234, 15.022046, 14.452234, 13.963908, 13.214750, 13.212184, 10.381022, - 10.375351, 4.753958, 4.750187, 4.748513, 15.783667, 15.788604, 15.715040, - 15.574608, 15.604897, 15.345511, 15.322323, 15.003579, 14.280362, 13.963611, - 13.214382, 13.212184, 10.381022, 10.375351, 4.753958, 4.750106, 4.750025, - 4.508804, 15.747709, 14.765834, 15.706678, 15.619092, 15.637946, 15.437393, - 14.705235, 13.886464, 13.092309, 12.499506, 12.601594, 10.380302, 10.375350, - 4.753958, 4.750026, 4.510253, 4.510173, 4.508580, 15.641901, 14.968111, - 15.663074, 15.583828, 15.420627, 14.983936, 13.912901, 13.425841, 11.601603, - 10.600757, 10.110971, 8.839811, 4.753363, 4.749963, 4.510190, 4.322919, - 4.322857, 4.321407, 15.545263, 14.859883, 15.429167, 15.185696, 14.527376, - 13.650042, 12.244185, 10.755706, 9.356137, 8.229212, 8.166627, 7.324414, - 4.511146, 4.322709, 4.322566, 4.322503, 4.322503, 4.321054, 15.151031, - 14.579126, 14.592456, 13.733213, 11.980508, 10.685709, 9.143695, 7.466555, - 6.434770, 5.659204, 5.592407, 5.356211, 4.597869, 3.456439, 3.456056, - 3.456176, 3.456176, 3.455018, 13.478598, 13.969965, 10.921203, 9.274388, - 7.530261, 6.614303, 5.617812, 4.558886, 4.008929, 3.739688, 3.597707, - 3.510418, 3.041638, 3.096611, 3.096750, 3.455008, 3.455038, 3.453880, - 11.982351, 11.102072, 6.384662, 5.366178, 4.365376, 3.782955, 3.285890, - 2.758904, 2.439067, 2.338593, 2.257332, 2.190385, 2.088145, 1.867744, - 1.867445, 1.196878, 0.929332, 0.928931, 6.882587, 5.102224, 3.928701, - 3.021205, 2.614349, 2.162491, 1.870802, 1.628127, 1.448370, 1.352404, - 1.349332, 1.277236, 1.128399, 0.928668, 0.928601, 0.928485, 0.928395, - 0.928084, 4.066496, 3.233175, 2.413117, 1.830193, 1.473572, 1.273461, - 1.065156, 0.929824, 0.844729, 0.777037, 0.754300, 0.759737, 0.658871, - 0.603118, 0.603209, 0.928096, 0.928205, 0.927893, 2.747433, 2.039019, - 1.400016, 1.123698, 0.918772, 0.744824, 0.627536, 0.528263, 0.480634, - 0.446093, 0.423444, 0.401394, 0.394353, 0.360914, 0.360903, 0.361012, - 0.361012, 0.360891, 1.709038, 1.258373, 0.985529, 0.673582, 0.559577, - 0.456411, 0.372560, 0.312622, 0.268425, 0.251698, 0.238132, 0.222477, - 0.209643, 0.165264, 0.165254, 0.165254, 0.165254, 0.165199, 1.088160, - 0.806677, 0.673453, 0.490758, 0.350173, 0.277724, 0.229342, 0.190245, - 0.158717, 0.138414, 0.132405, 0.123800, 0.120550, 0.128355, 0.142808, - 0.142812, 0.142800, 0.142752, 0.806227, 0.588621, 0.490714, 0.350136, - 0.236497, 0.188583, 0.143991, 0.115039, 0.097317, 0.081406, 0.071159, - 0.067980, 0.062769, 0.066575, 0.066581, 0.066569, 0.030318, 0.030291, - 0.588339, 0.456572, 0.302189, 0.236473, 0.188564, 0.126491, 0.101248, - 0.075242, 0.059591, 0.051942, 0.042824, 0.037390, 0.034523, 0.030277, - 0.030275, 0.030275, 0.030258, 0.014677, 0.456374, 0.302172, 0.236448, - 0.164278, 0.126481, 0.094667, 0.068489, 0.053835, 0.038513, 0.031335, - 0.028947, 0.022753, 0.019347, 0.014676, 0.014675, 0.014674, 0.014674, - 0.014664, 0.302014, 0.221625, 0.164273, 0.126473, 0.094667, 0.068483, - 0.053831, 0.034298, 0.027445, 0.022220, 0.016315, 0.015692, 0.012949, - 0.009448, 0.009442, 0.007914, 0.007913, 0.007910, 0.221524, 0.164268, - 0.126473, 0.094667, 0.068480, 0.044800, 0.034295, 0.027442, 0.019666, - 0.014389, 0.011041, 0.011550, 0.009117, 0.021326, 0.007915, 0.007911, - 0.007911, 0.007908, 0.164193, 0.126473, 0.094667, 0.068480, 0.044800, - 0.034291, 0.027442, 0.019665, 0.014388, 0.008515, 0.008320, 0.009117, - 0.007357, 0.004348, 0.004343, 0.007908, 0.007910, 0.007907, 0.125623, - 0.094667, 0.068480, 0.044800, 0.034289, 0.023364, 0.019663, 0.011887, - 0.008514, 0.008318, 0.007208, 0.007208, 0.007206, 0.004342, 0.004341, - 0.004342, 0.004342, 0.004341, 0.094624, 0.068480, 0.044800, 0.034289, - 0.023364, 0.019662, 0.011887, 0.008514, 0.008318, 0.007208, 0.007207, - 0.007207, 0.007206, 0.004342, 0.004341, 0.004341, 0.004341, 0.004340, - 0.068449, 0.044800, 0.034289, 0.023364, 0.019662, 0.011887, 0.008514, - 0.008318, 0.007208, 0.007207, 0.007207, 0.007207, 0.007206, 0.004343, - 0.004341, 0.004341, 0.004341, 0.004340, 0.044777, 0.034289, 0.023364, - 0.019662, 0.011887, 0.008514, 0.008318, 0.007208, 0.007207, 0.007207, - 0.007207, 0.007207, 0.007207, 0.007205, 0.004342, 0.004341, 0.004341, - 0.004340, 0.034274, 0.023364, 0.019662, 0.011887, 0.008514, 0.008318, - 0.007208, 0.007207, 0.007207, 0.007207, 0.007207, 0.007207, 0.007207, - 0.007206, 0.004342, 0.004341, 0.004341, 0.004340, 0.023353, 0.019662, - 0.011887, 0.008514, 0.008318, 0.007208, 0.007207, 0.007207, 0.007207, - 0.007207, 0.007207, 0.007207, 0.007207, 0.007206, 0.004343, 0.004341, - 0.004341, 0.004340, 0.019650, 0.011884, 0.008511, 0.008316, 0.007205, - 0.007205, 0.007205, 0.007205, 0.007205, 0.007205, 0.007205, 0.007205, - 0.007205, 0.007205, 0.007203, 0.004341, 0.004340, 0.004338, +static const double surffit_dist_params[7] = { + 1.475844, 4.328362, -5.680233, -0.500994, 0.554585, 4.839478, -0.695837 }; +static void rate_surffit_model_params_lookup(BLOCK_SIZE bsize, double xm, + double *rpar) { + const int cat = bsize_surffit_model_cat_lookup[bsize]; + rpar[0] = surffit_rate_params[cat][0] + surffit_rate_params[cat][1] * xm; + rpar[1] = surffit_rate_params[cat][2] + surffit_rate_params[cat][3] * xm; +} + +static void dist_surffit_model_params_lookup(BLOCK_SIZE bsize, double xm, + double *dpar) { + (void)bsize; + const double *params = surffit_dist_params; + dpar[0] = params[0] + params[1] / (1 + exp((xm + params[2]) * params[3])); + dpar[1] = params[4] + params[5] * exp(params[6] * xm); +} + void av1_model_rd_surffit(BLOCK_SIZE bsize, double sse_norm, double xm, - double yl, double *rate_f, double *dist_f) { + double yl, double *rate_f, double *distbysse_f) { (void)sse_norm; - const double x_start = -0.5; - const double x_end = 16.5; - const double x_step = 1.0; - const double y_start = -15.5; - const double y_end = 16.5; - const double y_step = 1.0; - const double epsilon = 1e-6; - const int stride = (int)rint((x_end - x_start) / x_step) + 1; - const int rcat = bsize_model_cat_lookup[bsize]; - (void)y_end; + double rpar[2], dpar[2]; + rate_surffit_model_params_lookup(bsize, xm, rpar); + dist_surffit_model_params_lookup(bsize, xm, dpar); - xm = AOMMAX(xm, x_start + x_step + epsilon); - xm = AOMMIN(xm, x_end - x_step - epsilon); - yl = AOMMAX(yl, y_start + y_step + epsilon); - yl = AOMMIN(yl, y_end - y_step - epsilon); - - const double y = (yl - y_start) / y_step; - const double x = (xm - x_start) / x_step; - - const int yi = (int)floor(y); - const int xi = (int)floor(x); - assert(xi > 0); - assert(yi > 0); - - const double yo = y - yi; - const double xo = x - xi; - const double *prate = &interp_rgrid_surf[rcat][(yi - 1) * stride + (xi - 1)]; - const double *pdist = &interp_dgrid_surf[(yi - 1) * stride + (xi - 1)]; - *rate_f = interp_bicubic(prate, stride, xo, yo); - *dist_f = interp_bicubic(pdist, stride, xo, yo); + *rate_f = get_rate_clamplinear(yl, rpar[0], rpar[1]); + *distbysse_f = get_dbysse_logistic(yl, dpar[0], dpar[1]); } static const double interp_rgrid_curv[4][65] = { @@ -1429,8 +923,8 @@ void av1_model_rd_curvfit(BLOCK_SIZE bsize, double sse_norm, double xqr, const double x_end = 16.5; const double x_step = 0.5; const double epsilon = 1e-6; - const int rcat = bsize_model_cat_lookup[bsize]; - const int dcat = sse_norm_model_cat_lookup(sse_norm); + const int rcat = bsize_curvfit_model_cat_lookup[bsize]; + const int dcat = sse_norm_curvfit_model_cat_lookup(sse_norm); (void)x_end; xqr = AOMMAX(xqr, x_start + x_step + epsilon); diff --git a/third_party/aom/av1/encoder/rd.h b/third_party/aom/av1/encoder/rd.h index 350eeb6d5f..ff4608343b 100644 --- a/third_party/aom/av1/encoder/rd.h +++ b/third_party/aom/av1/encoder/rd.h @@ -318,25 +318,6 @@ static INLINE void av1_init_rd_stats(RD_STATS *rd_stats) { } } #endif -#if CONFIG_ONE_PASS_SVM - rd_stats->eob = 0; - rd_stats->eob_0 = 0; - rd_stats->eob_1 = 0; - rd_stats->eob_2 = 0; - rd_stats->eob_3 = 0; - - rd_stats->rd = 0; - rd_stats->rd_0 = 0; - rd_stats->rd_1 = 0; - rd_stats->rd_2 = 0; - rd_stats->rd_3 = 0; - - rd_stats->y_sse = 0; - rd_stats->sse_0 = 0; - rd_stats->sse_1 = 0; - rd_stats->sse_2 = 0; - rd_stats->sse_3 = 0; -#endif } static INLINE void av1_invalid_rd_stats(RD_STATS *rd_stats) { @@ -364,30 +345,6 @@ static INLINE void av1_invalid_rd_stats(RD_STATS *rd_stats) { } } #endif -#if CONFIG_ONE_PASS_SVM - // TODO(chiyotsai@google.com): Change invalid values to INT_MAX and - // INT64_MAX. Currently there are some code paths where rd_stats's properties - // are set directly without calling av1_init_rd_stats, so changing it now will - // break this speed feature. Need to hunt down all places where rd_stats is - // used without initialized. - rd_stats->eob = 0; - rd_stats->eob_0 = 0; - rd_stats->eob_1 = 0; - rd_stats->eob_2 = 0; - rd_stats->eob_3 = 0; - - rd_stats->rd = 0; - rd_stats->rd_0 = 0; - rd_stats->rd_1 = 0; - rd_stats->rd_2 = 0; - rd_stats->rd_3 = 0; - - rd_stats->y_sse = 0; - rd_stats->sse_0 = 0; - rd_stats->sse_1 = 0; - rd_stats->sse_2 = 0; - rd_stats->sse_3 = 0; -#endif } static INLINE void av1_merge_rd_stats(RD_STATS *rd_stats_dst, @@ -421,222 +378,8 @@ static INLINE void av1_merge_rd_stats(RD_STATS *rd_stats_dst, } } #endif -#if CONFIG_ONE_PASS_SVM - rd_stats_dst->eob += rd_stats_src->eob; - rd_stats_dst->eob_0 += rd_stats_src->eob_0; - rd_stats_dst->eob_1 += rd_stats_src->eob_1; - rd_stats_dst->eob_2 += rd_stats_src->eob_2; - rd_stats_dst->eob_3 += rd_stats_src->eob_3; - - rd_stats_dst->rd += rd_stats_src->rd; - rd_stats_dst->rd_0 += rd_stats_src->rd_0; - rd_stats_dst->rd_1 += rd_stats_src->rd_1; - rd_stats_dst->rd_2 += rd_stats_src->rd_2; - rd_stats_dst->rd_3 += rd_stats_src->rd_3; - - rd_stats_dst->y_sse += rd_stats_src->y_sse; - rd_stats_dst->sse_0 += rd_stats_src->sse_0; - rd_stats_dst->sse_1 += rd_stats_src->sse_1; - rd_stats_dst->sse_2 += rd_stats_src->sse_2; - rd_stats_dst->sse_3 += rd_stats_src->sse_3; -#endif } -#if CONFIG_ONE_PASS_SVM -static INLINE void av1_add_reg_stat(RD_STATS *rd_stats, int eob, int64_t rd, - int64_t sse, int blk_row, int blk_col, - BLOCK_SIZE bsize, BLOCK_SIZE crop_bsize) { - // NOTE: Currently the calculation of regional features works by assuming - // bsize is square so that each transform block of size crop_bsize either - // 1. locates completely within a quadrant or - // 2. is exactly half of bsize or - // 3. is the entire prediction block - // Size of TX block and SB - const int block_width_mi = mi_size_wide[bsize]; - const int block_height_mi = mi_size_high[bsize]; - const int crop_width_mi = mi_size_wide[crop_bsize]; - const int crop_height_mi = mi_size_high[crop_bsize]; - - // Increment the eob proportionally to how much the tx_block overlaps with - // each quadrant. We will scale it by MAX_MIB_SIZE * MAX_MIB_SIZE to avoid - // being truncated. - const int max_scaling_factor = MAX_MIB_SIZE * MAX_MIB_SIZE; - - // Update the stats - rd_stats->eob = eob; - rd_stats->rd = rd; - rd_stats->y_sse = sse; - - if (crop_width_mi <= block_width_mi / 2 && - crop_height_mi <= block_width_mi / 2) { - // The transform block lies completely in a quadrant. - const int scaling_factor = max_scaling_factor; - const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor, - r_sse = sse * scaling_factor; - - if (blk_row < block_height_mi / 2 && blk_col < block_width_mi / 2) { - rd_stats->eob_0 = r_eob; - rd_stats->rd_0 = r_rd; - rd_stats->sse_0 = r_sse; - } else if (blk_row < block_height_mi / 2 && blk_col >= block_width_mi / 2) { - rd_stats->eob_1 = r_eob; - rd_stats->rd_1 = r_rd; - rd_stats->sse_1 = r_sse; - } else if (blk_row >= block_height_mi / 2 && blk_col < block_width_mi / 2) { - rd_stats->eob_2 = r_eob; - rd_stats->rd_2 = r_rd; - rd_stats->sse_2 = r_sse; - } else { - rd_stats->eob_3 = r_eob; - rd_stats->rd_3 = r_rd; - rd_stats->sse_3 = r_sse; - } - } else if (crop_height_mi == block_height_mi && - crop_width_mi == block_width_mi) { - // The transform block is the whole prediction block - const int scaling_factor = max_scaling_factor; - const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor, - r_sse = sse * scaling_factor; - - rd_stats->eob_0 = r_eob; - rd_stats->rd_0 = r_rd; - rd_stats->sse_0 = r_sse; - - rd_stats->eob_1 = r_eob; - rd_stats->rd_1 = r_rd; - rd_stats->sse_1 = r_sse; - - rd_stats->eob_2 = r_eob; - rd_stats->rd_2 = r_rd; - rd_stats->sse_2 = r_sse; - - rd_stats->eob_3 = r_eob; - rd_stats->rd_3 = r_rd; - rd_stats->sse_3 = r_sse; - } else if (crop_height_mi == block_height_mi) { - // The tranform block is a vertical block - const int scaling_factor = max_scaling_factor / 2; - const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor, - r_sse = sse * scaling_factor; - - if (blk_col < block_width_mi / 2) { - rd_stats->eob_0 = r_eob; - rd_stats->rd_0 = r_rd; - rd_stats->sse_0 = r_sse; - - rd_stats->eob_2 = r_eob; - rd_stats->rd_2 = r_rd; - rd_stats->sse_2 = r_sse; - } else { - rd_stats->eob_1 = r_eob; - rd_stats->rd_1 = r_rd; - rd_stats->sse_1 = r_sse; - - rd_stats->eob_3 = r_eob; - rd_stats->rd_3 = r_rd; - rd_stats->sse_3 = r_sse; - } - } else if (crop_width_mi == block_width_mi) { - // The tranform block is a horizontal block half the size of predition block - const int scaling_factor = max_scaling_factor / 2; - const int r_eob = eob * scaling_factor, r_rd = rd * scaling_factor, - r_sse = sse * scaling_factor; - - if (blk_row < block_height_mi / 2) { - rd_stats->eob_0 = r_eob; - rd_stats->rd_0 = r_rd; - rd_stats->sse_0 = r_sse; - - rd_stats->eob_1 = r_eob; - rd_stats->rd_1 = r_rd; - rd_stats->sse_1 = r_sse; - } else { - rd_stats->eob_2 = r_eob; - rd_stats->rd_2 = r_rd; - rd_stats->sse_2 = r_sse; - - rd_stats->eob_3 = r_eob; - rd_stats->rd_3 = r_rd; - rd_stats->sse_3 = r_sse; - } - } else { - assert(0 && "Unexpected transform size"); - } -} - -static INLINE void av1_reg_stat_skipmode_update(RD_STATS *rd_stats, - int rdmult) { - // Update the stats - rd_stats->eob = 0; - rd_stats->eob_0 = 0; - rd_stats->eob_1 = 0; - rd_stats->eob_2 = 0; - rd_stats->eob_3 = 0; - - rd_stats->rd = RDCOST(rdmult, 0, rd_stats->sse); - rd_stats->rd_0 = RDCOST(rdmult, 0, rd_stats->sse_0); - rd_stats->rd_1 = RDCOST(rdmult, 0, rd_stats->sse_1); - rd_stats->rd_2 = RDCOST(rdmult, 0, rd_stats->sse_2); - rd_stats->rd_3 = RDCOST(rdmult, 0, rd_stats->sse_3); -} - -static INLINE void av1_copy_reg_stat(RD_STATS *rd_stats_dst, - RD_STATS *rd_stats_src) { - rd_stats_dst->eob = rd_stats_src->eob; - rd_stats_dst->eob_0 = rd_stats_src->eob_0; - rd_stats_dst->eob_1 = rd_stats_src->eob_1; - rd_stats_dst->eob_2 = rd_stats_src->eob_2; - rd_stats_dst->eob_3 = rd_stats_src->eob_3; - - rd_stats_dst->rd = rd_stats_src->rd; - rd_stats_dst->rd_0 = rd_stats_src->rd_0; - rd_stats_dst->rd_1 = rd_stats_src->rd_1; - rd_stats_dst->rd_2 = rd_stats_src->rd_2; - rd_stats_dst->rd_3 = rd_stats_src->rd_3; - - rd_stats_dst->y_sse = rd_stats_src->y_sse; - rd_stats_dst->sse_0 = rd_stats_src->sse_0; - rd_stats_dst->sse_1 = rd_stats_src->sse_1; - rd_stats_dst->sse_2 = rd_stats_src->sse_2; - rd_stats_dst->sse_3 = rd_stats_src->sse_3; -} - -static INLINE void av1_unpack_reg_stat(RD_STATS *rd_stats, int *eob, int *eob_0, - int *eob_1, int *eob_2, int *eob_3, - int64_t *rd, int64_t *rd_0, - int64_t *rd_1, int64_t *rd_2, - int64_t *rd_3) { - *rd = rd_stats->rd; - *rd_0 = rd_stats->rd_0; - *rd_1 = rd_stats->rd_1; - *rd_2 = rd_stats->rd_2; - *rd_3 = rd_stats->rd_3; - - *eob = rd_stats->eob; - *eob_0 = rd_stats->eob_0; - *eob_1 = rd_stats->eob_1; - *eob_2 = rd_stats->eob_2; - *eob_3 = rd_stats->eob_3; -} - -static INLINE void av1_set_reg_stat(RD_STATS *rd_stats, int eob, int eob_0, - int eob_1, int eob_2, int eob_3, int64_t rd, - int64_t rd_0, int64_t rd_1, int64_t rd_2, - int64_t rd_3) { - rd_stats->rd = rd; - rd_stats->rd_0 = rd_0; - rd_stats->rd_1 = rd_1; - rd_stats->rd_2 = rd_2; - rd_stats->rd_3 = rd_3; - - rd_stats->eob = eob; - rd_stats->eob_0 = eob_0; - rd_stats->eob_1 = eob_1; - rd_stats->eob_2 = eob_2; - rd_stats->eob_3 = eob_3; -} -#endif - struct TileInfo; struct TileDataEnc; struct AV1_COMP; diff --git a/third_party/aom/av1/encoder/rdopt.c b/third_party/aom/av1/encoder/rdopt.c index 0be76e4cb2..5e6054e52f 100644 --- a/third_party/aom/av1/encoder/rdopt.c +++ b/third_party/aom/av1/encoder/rdopt.c @@ -164,10 +164,6 @@ static const InterpFilters filter_sets[DUAL_FILTER_SET_SIZE] = { 0x00000002, 0x00010002, 0x00020002, // y = 2 }; -#define SECOND_REF_FRAME_MASK \ - ((1 << ALTREF_FRAME) | (1 << ALTREF2_FRAME) | (1 << BWDREF_FRAME) | \ - (1 << GOLDEN_FRAME) | (1 << LAST2_FRAME) | 0x01) - static const double ADST_FLIP_SVM[8] = { /* vertical */ -6.6623, -2.8062, -3.2531, 3.1671, @@ -180,10 +176,6 @@ typedef struct { MV_REFERENCE_FRAME ref_frame[2]; } MODE_DEFINITION; -typedef struct { - MV_REFERENCE_FRAME ref_frame[2]; -} REF_DEFINITION; - enum { FTXS_NONE = 0, FTXS_DCT_AND_1D_DCT_ONLY = 1 << 0, @@ -203,6 +195,7 @@ struct rdcost_block_args { int incomplete_exit; int use_fast_coef_costing; FAST_TX_SEARCH_MODE ftxs_mode; + int skip_trellis; }; #define LAST_NEW_MV_INDEX 6 @@ -866,14 +859,25 @@ static void inter_mode_data_push(TileDataEnc *tile_data, BLOCK_SIZE bsize, } static void inter_modes_info_push(InterModesInfo *inter_modes_info, - int mode_rate, int64_t sse, int64_t est_rd, + int mode_rate, int64_t sse, int64_t rd, + bool true_rd, uint8_t *blk_skip, + RD_STATS *rd_cost, RD_STATS *rd_cost_y, + RD_STATS *rd_cost_uv, const MB_MODE_INFO *mbmi) { const int num = inter_modes_info->num; assert(num < MAX_INTER_MODES); inter_modes_info->mbmi_arr[num] = *mbmi; inter_modes_info->mode_rate_arr[num] = mode_rate; inter_modes_info->sse_arr[num] = sse; - inter_modes_info->est_rd_arr[num] = est_rd; + inter_modes_info->est_rd_arr[num] = rd; + inter_modes_info->true_rd_arr[num] = true_rd; + if (blk_skip != NULL) { + memcpy(inter_modes_info->blk_skip_arr[num], blk_skip, + sizeof(blk_skip[0]) * MAX_MIB_SIZE * MAX_MIB_SIZE); + } + inter_modes_info->rd_cost_arr[num] = *rd_cost; + inter_modes_info->rd_cost_y_arr[num] = *rd_cost_y; + inter_modes_info->rd_cost_uv_arr[num] = *rd_cost_uv; ++inter_modes_info->num; } @@ -2982,7 +2986,7 @@ static void model_rd_with_curvfit(const AV1_COMP *const cpi, aom_clear_system_state(); const double sse_norm = (double)sse / num_samples; const double qstepsqr = (double)qstep * qstep; - const double xqr = log(sse_norm / qstepsqr) / log(2.0); + const double xqr = log2(sse_norm / qstepsqr); double rate_f, dist_by_sse_norm_f; av1_model_rd_curvfit(plane_bsize, sse_norm, xqr, &rate_f, @@ -3071,8 +3075,8 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, const TXB_CTX *const txb_ctx, FAST_TX_SEARCH_MODE ftxs_mode, - int use_fast_coef_costing, int64_t ref_best_rd, - RD_STATS *best_rd_stats) { + int use_fast_coef_costing, int skip_trellis, + int64_t ref_best_rd, RD_STATS *best_rd_stats) { const AV1_COMMON *cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; struct macroblockd_plane *const pd = &xd->plane[plane]; @@ -3102,6 +3106,9 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, (mi_row + mi_size_high[plane_bsize] < xd->tile.mi_row_end) && mi_col >= xd->tile.mi_col_start && (mi_col + mi_size_wide[plane_bsize] < xd->tile.mi_col_end); + skip_trellis |= + cpi->optimize_seg_arr[mbmi->segment_id] == NO_TRELLIS_OPT || + cpi->optimize_seg_arr[mbmi->segment_id] == FINAL_PASS_TRELLIS_OPT; if (within_border && cpi->sf.use_intra_txb_hash && frame_is_intra_only(cm) && !is_inter && plane == 0 && tx_size_wide[tx_size] == tx_size_high[tx_size]) { @@ -3188,6 +3195,13 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, } } } + + if (cpi->oxcf.enable_flip_idtx == 0) { + for (TX_TYPE tx_type = FLIPADST_DCT; tx_type <= H_FLIPADST; ++tx_type) { + allowed_tx_mask &= ~(1 << tx_type); + } + } + // Need to have at least one transform type allowed. if (allowed_tx_mask == 0) { txk_start = txk_end = (plane ? uv_tx_type : DCT_DCT); @@ -3228,7 +3242,7 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, const uint16_t *eobs_ptr = x->plane[plane].eobs; // Used mse based threshold logic to take decision of R-D of optimization of - // coeffs. For snaller residuals, coeff optimization would be helpful. For + // coeffs. For smaller residuals, coeff optimization would be helpful. For // larger residuals, R-D optimization may not be effective. // TODO(any): Experiment with variance and mean based thresholds perform_block_coeff_opt = (block_mse_q8 <= cpi->coeff_opt_dist_threshold); @@ -3238,8 +3252,7 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, if (plane == 0) mbmi->txk_type[txk_type_idx] = tx_type; RD_STATS this_rd_stats; av1_invalid_rd_stats(&this_rd_stats); - if ((cpi->optimize_seg_arr[mbmi->segment_id] != FULL_TRELLIS_OPT) || - (!perform_block_coeff_opt)) { + if (skip_trellis || (!perform_block_coeff_opt)) { av1_xform_quant( cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type, USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP); @@ -3259,8 +3272,8 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, RDCOST(x->rdmult, 0, AOMMIN(this_rd_stats.dist, this_rd_stats.sse)); if (dist_cost_estimate - (dist_cost_estimate >> 3) > best_rd_) continue; } - av1_optimize_b(cpi, x, plane, block, tx_size, tx_type, txb_ctx, 1, - &rate_cost); + av1_optimize_b(cpi, x, plane, block, tx_size, tx_type, txb_ctx, + cpi->sf.trellis_eob_fast, &rate_cost); } if (eobs_ptr[block] == 0) { // When eob is 0, pixel domain distortion is more efficient and accurate. @@ -3269,8 +3282,38 @@ static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, dist_block_tx_domain(x, plane, block, tx_size, &this_rd_stats.dist, &this_rd_stats.sse); } else { - this_rd_stats.dist = dist_block_px_domain( - cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size); + int64_t sse_diff = INT64_MAX; + // high_energy threshold assumes that every pixel within a txfm block + // has a residue energy of at least 25% of the maximum, i.e. 128 * 128 + // for 8 bit, then the threshold is scaled based on input bit depth. + const int64_t high_energy_thresh = + ((int64_t)128 * 128 * tx_size_2d[tx_size]) << ((xd->bd - 8) * 2); + const int is_high_energy = (block_sse >= high_energy_thresh); + if (tx_size == TX_64X64 || is_high_energy) { + // Because 3 out 4 quadrants of transform coefficients are forced to + // zero, the inverse transform has a tendency to overflow. sse_diff + // is effectively the energy of those 3 quadrants, here we use it + // to decide if we should do pixel domain distortion. If the energy + // is mostly in first quadrant, then it is unlikely that we have + // overflow issue in inverse transform. + dist_block_tx_domain(x, plane, block, tx_size, &this_rd_stats.dist, + &this_rd_stats.sse); + sse_diff = block_sse - this_rd_stats.sse; + } + if (tx_size != TX_64X64 || !is_high_energy || + (sse_diff * 2) < this_rd_stats.sse) { + const int64_t tx_domain_dist = this_rd_stats.dist; + this_rd_stats.dist = dist_block_px_domain( + cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size); + // For high energy blocks, occasionally, the pixel domain distortion + // can be artificially low due to clamping at reconstruction stage + // even when inverse transform output is hugely different from the + // actual residue. + if (is_high_energy && this_rd_stats.dist < tx_domain_dist) + this_rd_stats.dist = tx_domain_dist; + } else { + this_rd_stats.dist += sse_diff; + } this_rd_stats.sse = block_sse; } @@ -3385,7 +3428,7 @@ RECON_INTRA: // if the last search tx_type is the best tx_type, we don't need to // do this again if (best_tx_type != last_tx_type) { - if (cpi->optimize_seg_arr[mbmi->segment_id] != FULL_TRELLIS_OPT) { + if (skip_trellis) { av1_xform_quant( cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, best_tx_type, @@ -3393,8 +3436,8 @@ RECON_INTRA: } else { av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, best_tx_type, AV1_XFORM_QUANT_FP); - av1_optimize_b(cpi, x, plane, block, tx_size, best_tx_type, txb_ctx, 1, - &rate_cost); + av1_optimize_b(cpi, x, plane, block, tx_size, best_tx_type, txb_ctx, + cpi->sf.trellis_eob_fast, &rate_cost); } } @@ -3443,7 +3486,8 @@ static void block_rd_txfm(int plane, int block, int blk_row, int blk_col, get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx); search_txk_type(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, &txb_ctx, args->ftxs_mode, args->use_fast_coef_costing, - args->best_rd - args->this_rd, &this_rd_stats); + args->skip_trellis, args->best_rd - args->this_rd, + &this_rd_stats); if (plane == AOM_PLANE_Y && xd->cfl.store_y) { assert(!is_inter || plane_bsize < BLOCK_8X8); @@ -3473,14 +3517,6 @@ static void block_rd_txfm(int plane, int block, int blk_row, int blk_col, this_rd_stats.skip &= !x->plane[plane].eobs[block]; -#if CONFIG_ONE_PASS_SVM - if (plane == AOM_PLANE_Y && plane_bsize >= BLOCK_8X8) { - const int eob = x->plane[plane].eobs[block]; - av1_add_reg_stat(&this_rd_stats, eob, rd, this_rd_stats.sse, blk_row, - blk_col, plane_bsize, txsize_to_bsize[tx_size]); - } -#endif - av1_merge_rd_stats(&args->rd_stats, &this_rd_stats); args->this_rd += rd; @@ -3492,7 +3528,7 @@ static void txfm_rd_in_plane(MACROBLOCK *x, const AV1_COMP *cpi, RD_STATS *rd_stats, int64_t ref_best_rd, int64_t this_rd, int plane, BLOCK_SIZE bsize, TX_SIZE tx_size, int use_fast_coef_casting, - FAST_TX_SEARCH_MODE ftxs_mode) { + FAST_TX_SEARCH_MODE ftxs_mode, int skip_trellis) { MACROBLOCKD *const xd = &x->e_mbd; const struct macroblockd_plane *const pd = &xd->plane[plane]; struct rdcost_block_args args; @@ -3503,6 +3539,7 @@ static void txfm_rd_in_plane(MACROBLOCK *x, const AV1_COMP *cpi, args.use_fast_coef_costing = use_fast_coef_casting; args.ftxs_mode = ftxs_mode; args.this_rd = this_rd; + args.skip_trellis = skip_trellis; av1_init_rd_stats(&args.rd_stats); if (!cpi->oxcf.enable_tx64 && txsize_sqr_up_map[tx_size] == TX_64X64) { @@ -3546,7 +3583,8 @@ static int tx_size_cost(const AV1_COMMON *const cm, const MACROBLOCK *const x, static int64_t txfm_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats, int64_t ref_best_rd, BLOCK_SIZE bs, - TX_SIZE tx_size, FAST_TX_SEARCH_MODE ftxs_mode) { + TX_SIZE tx_size, FAST_TX_SEARCH_MODE ftxs_mode, + int skip_trellis) { const AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; @@ -3580,7 +3618,7 @@ static int64_t txfm_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, mbmi->tx_size = tx_size; txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, AOMMIN(this_rd, skip_rd), AOM_PLANE_Y, bs, tx_size, cpi->sf.use_fast_coef_costing, - ftxs_mode); + ftxs_mode, skip_trellis); if (rd_stats->rate == INT_MAX) return INT64_MAX; // rdstats->rate should include all the rate except skip/non-skip cost as the @@ -3590,16 +3628,8 @@ static int64_t txfm_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, if (rd_stats->skip) { if (is_inter) { rd = RDCOST(x->rdmult, s1, rd_stats->sse); -#if CONFIG_ONE_PASS_SVM - // TODO(chiyotsai@google.com): Investigate if these updates are really - // needed. - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); -#endif } else { rd = RDCOST(x->rdmult, s1 + r_tx_size * tx_select, rd_stats->sse); -#if CONFIG_ONE_PASS_SVM - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); -#endif rd_stats->rate += r_tx_size * tx_select; } } else { @@ -3623,13 +3653,16 @@ static int64_t txfm_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, static int64_t estimate_yrd_for_sb(const AV1_COMP *const cpi, BLOCK_SIZE bs, MACROBLOCK *x, int64_t ref_best_rd, RD_STATS *rd_stats) { + MACROBLOCKD *const xd = &x->e_mbd; av1_subtract_plane(x, bs, 0); x->rd_model = LOW_TXFM_RD; - const int64_t rd = txfm_yrd(cpi, x, rd_stats, ref_best_rd, bs, - max_txsize_rect_lookup[bs], FTXS_NONE); + int skip_trellis = cpi->optimize_seg_arr[xd->mi[0]->segment_id] == + NO_ESTIMATE_YRD_TRELLIS_OPT; + const int64_t rd = + txfm_yrd(cpi, x, rd_stats, ref_best_rd, bs, max_txsize_rect_lookup[bs], + FTXS_NONE, skip_trellis); x->rd_model = FULL_TXFM_RD; if (rd != INT64_MAX) { - MACROBLOCKD *const xd = &x->e_mbd; const int skip_ctx = av1_get_skip_context(xd); if (rd_stats->skip) { const int s1 = x->skip_cost[skip_ctx][1]; @@ -3664,7 +3697,7 @@ static void choose_largest_tx_size(const AV1_COMP *const cpi, MACROBLOCK *x, txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, AOMMIN(this_rd, skip_rd), AOM_PLANE_Y, bs, mbmi->tx_size, - cpi->sf.use_fast_coef_costing, FTXS_NONE); + cpi->sf.use_fast_coef_costing, FTXS_NONE, 0); // Reset the pruning flags. av1_zero(x->tx_search_prune); x->tx_split_prune_flag = 0; @@ -3679,7 +3712,7 @@ static void choose_smallest_tx_size(const AV1_COMP *const cpi, MACROBLOCK *x, mbmi->tx_size = TX_4X4; // TODO(any) : Pass this_rd based on skip/non-skip cost txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, 0, 0, bs, mbmi->tx_size, - cpi->sf.use_fast_coef_costing, FTXS_NONE); + cpi->sf.use_fast_coef_costing, FTXS_NONE, 0); } static INLINE int bsize_to_num_blk(BLOCK_SIZE bsize) { @@ -3717,16 +3750,16 @@ static void choose_tx_size_type_from_rd(const AV1_COMP *const cpi, const TX_SIZE max_rect_tx_size = max_txsize_rect_lookup[bs]; const int tx_select = cm->tx_mode == TX_MODE_SELECT; int start_tx; - int depth; + int depth, init_depth; if (tx_select) { start_tx = max_rect_tx_size; - depth = get_search_init_depth(mi_size_wide[bs], mi_size_high[bs], - is_inter_block(mbmi), &cpi->sf); + init_depth = get_search_init_depth(mi_size_wide[bs], mi_size_high[bs], + is_inter_block(mbmi), &cpi->sf); } else { const TX_SIZE chosen_tx_size = tx_size_from_tx_mode(bs, cm->tx_mode); start_tx = chosen_tx_size; - depth = MAX_TX_DEPTH; + init_depth = MAX_TX_DEPTH; } prune_tx(cpi, bs, x, xd, EXT_TX_SET_ALL16); @@ -3737,6 +3770,8 @@ static void choose_tx_size_type_from_rd(const AV1_COMP *const cpi, int64_t best_rd = INT64_MAX; const int n4 = bsize_to_num_blk(bs); x->rd_model = FULL_TXFM_RD; + depth = init_depth; + int64_t rd[MAX_TX_DEPTH + 1] = { INT64_MAX, INT64_MAX, INT64_MAX }; for (int n = start_tx; depth <= MAX_TX_DEPTH; depth++, n = sub_tx_size_map[n]) { #if CONFIG_DIST_8X8 @@ -3747,18 +3782,24 @@ static void choose_tx_size_type_from_rd(const AV1_COMP *const cpi, if (!cpi->oxcf.enable_tx64 && txsize_sqr_up_map[n] == TX_64X64) continue; RD_STATS this_rd_stats; - const int64_t rd = - txfm_yrd(cpi, x, &this_rd_stats, ref_best_rd, bs, n, FTXS_NONE); + rd[depth] = + txfm_yrd(cpi, x, &this_rd_stats, ref_best_rd, bs, n, FTXS_NONE, 0); - if (rd < best_rd) { + if (rd[depth] < best_rd) { memcpy(best_txk_type, mbmi->txk_type, sizeof(best_txk_type[0]) * TXK_TYPE_BUF_LEN); memcpy(best_blk_skip, x->blk_skip, sizeof(best_blk_skip[0]) * n4); best_tx_size = n; - best_rd = rd; + best_rd = rd[depth]; *rd_stats = this_rd_stats; } if (n == TX_4X4) break; + // If we are searching three depths, prune the smallest size depending + // on rd results for the first two depths for low contrast blocks. + if (depth > init_depth && depth != MAX_TX_DEPTH && + x->source_variance < 256) { + if (rd[depth - 1] != INT64_MAX && rd[depth] > rd[depth - 1]) break; + } } if (rd_stats->rate != INT_MAX) { @@ -3773,14 +3814,245 @@ static void choose_tx_size_type_from_rd(const AV1_COMP *const cpi, x->tx_split_prune_flag = 0; } +// origin_threshold * 128 / 100 +static const uint32_t skip_pred_threshold[3][BLOCK_SIZES_ALL] = { + { + 64, 64, 64, 70, 60, 60, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 64, 64, 70, 70, 68, 68, + }, + { + 88, 88, 88, 86, 87, 87, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 88, 88, 86, 86, 68, 68, + }, + { + 90, 93, 93, 90, 93, 93, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 90, 90, 90, 90, 74, 74, + }, +}; + +// lookup table for predict_skip_flag +// int max_tx_size = max_txsize_rect_lookup[bsize]; +// if (tx_size_high[max_tx_size] > 16 || tx_size_wide[max_tx_size] > 16) +// max_tx_size = AOMMIN(max_txsize_lookup[bsize], TX_16X16); +static const TX_SIZE max_predict_sf_tx_size[BLOCK_SIZES_ALL] = { + TX_4X4, TX_4X8, TX_8X4, TX_8X8, TX_8X16, TX_16X8, + TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_16X16, + TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_4X16, TX_16X4, + TX_8X8, TX_8X8, TX_16X16, TX_16X16, +}; + +// Uses simple features on top of DCT coefficients to quickly predict +// whether optimal RD decision is to skip encoding the residual. +// The sse value is stored in dist. +static int predict_skip_flag(MACROBLOCK *x, BLOCK_SIZE bsize, int64_t *dist, + int reduced_tx_set) { + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const MACROBLOCKD *xd = &x->e_mbd; + const int16_t dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd); + + *dist = pixel_diff_dist(x, 0, 0, 0, bsize, bsize, NULL); + + const int64_t mse = *dist / bw / bh; + // Normalized quantizer takes the transform upscaling factor (8 for tx size + // smaller than 32) into account. + const int16_t normalized_dc_q = dc_q >> 3; + const int64_t mse_thresh = (int64_t)normalized_dc_q * normalized_dc_q / 8; + // Predict not to skip when mse is larger than threshold. + if (mse > mse_thresh) return 0; + + const int max_tx_size = max_predict_sf_tx_size[bsize]; + const int tx_h = tx_size_high[max_tx_size]; + const int tx_w = tx_size_wide[max_tx_size]; + DECLARE_ALIGNED(32, tran_low_t, coefs[32 * 32]); + TxfmParam param; + param.tx_type = DCT_DCT; + param.tx_size = max_tx_size; + param.bd = xd->bd; + param.is_hbd = is_cur_buf_hbd(xd); + param.lossless = 0; + param.tx_set_type = av1_get_ext_tx_set_type( + param.tx_size, is_inter_block(xd->mi[0]), reduced_tx_set); + const int bd_idx = (xd->bd == 8) ? 0 : ((xd->bd == 10) ? 1 : 2); + const uint32_t max_qcoef_thresh = skip_pred_threshold[bd_idx][bsize]; + const int16_t *src_diff = x->plane[0].src_diff; + const int n_coeff = tx_w * tx_h; + const int16_t ac_q = av1_ac_quant_QTX(x->qindex, 0, xd->bd); + const uint32_t dc_thresh = max_qcoef_thresh * dc_q; + const uint32_t ac_thresh = max_qcoef_thresh * ac_q; + for (int row = 0; row < bh; row += tx_h) { + for (int col = 0; col < bw; col += tx_w) { + av1_fwd_txfm(src_diff + col, coefs, bw, ¶m); + // Operating on TX domain, not pixels; we want the QTX quantizers + const uint32_t dc_coef = (((uint32_t)abs(coefs[0])) << 7); + if (dc_coef >= dc_thresh) return 0; + for (int i = 1; i < n_coeff; ++i) { + const uint32_t ac_coef = (((uint32_t)abs(coefs[i])) << 7); + if (ac_coef >= ac_thresh) return 0; + } + } + src_diff += tx_h * bw; + } + return 1; +} + +// Used to set proper context for early termination with skip = 1. +static void set_skip_flag(MACROBLOCK *x, RD_STATS *rd_stats, int bsize, + int64_t dist) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int n4 = bsize_to_num_blk(bsize); + const TX_SIZE tx_size = max_txsize_rect_lookup[bsize]; + memset(mbmi->txk_type, DCT_DCT, sizeof(mbmi->txk_type[0]) * TXK_TYPE_BUF_LEN); + memset(mbmi->inter_tx_size, tx_size, sizeof(mbmi->inter_tx_size)); + mbmi->tx_size = tx_size; + for (int i = 0; i < n4; ++i) set_blk_skip(x, 0, i, 1); + rd_stats->skip = 1; + if (is_cur_buf_hbd(xd)) dist = ROUND_POWER_OF_TWO(dist, (xd->bd - 8) * 2); + rd_stats->dist = rd_stats->sse = (dist << 4); + // Though decision is to make the block as skip based on luma stats, + // it is possible that block becomes non skip after chroma rd. In addition + // intermediate non skip costs calculated by caller function will be + // incorrect, if rate is set as zero (i.e., if zero_blk_rate is not + // accounted). Hence intermediate rate is populated to code the luma tx blks + // as skip, the caller function based on final rd decision (i.e., skip vs + // non-skip) sets the final rate accordingly. Here the rate populated + // corresponds to coding all the tx blocks with zero_blk_rate (based on max tx + // size possible) in the current block. Eg: For 128*128 block, rate would be + // 4 * zero_blk_rate where zero_blk_rate corresponds to coding of one 64x64 tx + // block as 'all zeros' + ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE]; + ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE]; + av1_get_entropy_contexts(bsize, &xd->plane[0], ctxa, ctxl); + ENTROPY_CONTEXT *ta = ctxa; + ENTROPY_CONTEXT *tl = ctxl; + const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); + TXB_CTX txb_ctx; + get_txb_ctx(bsize, tx_size, 0, ta, tl, &txb_ctx); + const int zero_blk_rate = x->coeff_costs[txs_ctx][PLANE_TYPE_Y] + .txb_skip_cost[txb_ctx.txb_skip_ctx][1]; + rd_stats->rate = zero_blk_rate * + (block_size_wide[bsize] >> tx_size_wide_log2[tx_size]) * + (block_size_high[bsize] >> tx_size_high_log2[tx_size]); +} + +static INLINE uint32_t get_block_residue_hash(MACROBLOCK *x, BLOCK_SIZE bsize) { + const int rows = block_size_high[bsize]; + const int cols = block_size_wide[bsize]; + const int16_t *diff = x->plane[0].src_diff; + const uint32_t hash = av1_get_crc32c_value(&x->mb_rd_record.crc_calculator, + (uint8_t *)diff, 2 * rows * cols); + return (hash << 5) + bsize; +} + +static void save_tx_rd_info(int n4, uint32_t hash, const MACROBLOCK *const x, + const RD_STATS *const rd_stats, + MB_RD_RECORD *tx_rd_record) { + int index; + if (tx_rd_record->num < RD_RECORD_BUFFER_LEN) { + index = + (tx_rd_record->index_start + tx_rd_record->num) % RD_RECORD_BUFFER_LEN; + ++tx_rd_record->num; + } else { + index = tx_rd_record->index_start; + tx_rd_record->index_start = + (tx_rd_record->index_start + 1) % RD_RECORD_BUFFER_LEN; + } + MB_RD_INFO *const tx_rd_info = &tx_rd_record->tx_rd_info[index]; + const MACROBLOCKD *const xd = &x->e_mbd; + const MB_MODE_INFO *const mbmi = xd->mi[0]; + tx_rd_info->hash_value = hash; + tx_rd_info->tx_size = mbmi->tx_size; + memcpy(tx_rd_info->blk_skip, x->blk_skip, + sizeof(tx_rd_info->blk_skip[0]) * n4); + av1_copy(tx_rd_info->inter_tx_size, mbmi->inter_tx_size); + av1_copy(tx_rd_info->txk_type, mbmi->txk_type); + tx_rd_info->rd_stats = *rd_stats; +} + +static void fetch_tx_rd_info(int n4, const MB_RD_INFO *const tx_rd_info, + RD_STATS *const rd_stats, MACROBLOCK *const x) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + mbmi->tx_size = tx_rd_info->tx_size; + memcpy(x->blk_skip, tx_rd_info->blk_skip, + sizeof(tx_rd_info->blk_skip[0]) * n4); + av1_copy(mbmi->inter_tx_size, tx_rd_info->inter_tx_size); + av1_copy(mbmi->txk_type, tx_rd_info->txk_type); + *rd_stats = tx_rd_info->rd_stats; +} + +static INLINE int32_t find_mb_rd_info(const MB_RD_RECORD *const mb_rd_record, + const int64_t ref_best_rd, + const uint32_t hash) { + int32_t match_index = -1; + if (ref_best_rd != INT64_MAX) { + for (int i = 0; i < mb_rd_record->num; ++i) { + const int index = (mb_rd_record->index_start + i) % RD_RECORD_BUFFER_LEN; + // If there is a match in the tx_rd_record, fetch the RD decision and + // terminate early. + if (mb_rd_record->tx_rd_info[index].hash_value == hash) { + match_index = index; + break; + } + } + } + return match_index; +} + static void super_block_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats, BLOCK_SIZE bs, int64_t ref_best_rd) { MACROBLOCKD *xd = &x->e_mbd; av1_init_rd_stats(rd_stats); - + int is_inter = is_inter_block(xd->mi[0]); assert(bs == xd->mi[0]->sb_type); + const int mi_row = -xd->mb_to_top_edge >> (3 + MI_SIZE_LOG2); + const int mi_col = -xd->mb_to_left_edge >> (3 + MI_SIZE_LOG2); + + uint32_t hash = 0; + int32_t match_index = -1; + MB_RD_RECORD *mb_rd_record = NULL; + const int within_border = mi_row >= xd->tile.mi_row_start && + (mi_row + mi_size_high[bs] < xd->tile.mi_row_end) && + mi_col >= xd->tile.mi_col_start && + (mi_col + mi_size_wide[bs] < xd->tile.mi_col_end); + const int is_mb_rd_hash_enabled = + (within_border && cpi->sf.use_mb_rd_hash && is_inter); + const int n4 = bsize_to_num_blk(bs); + if (is_mb_rd_hash_enabled) { + hash = get_block_residue_hash(x, bs); + mb_rd_record = &x->mb_rd_record; + match_index = find_mb_rd_info(mb_rd_record, ref_best_rd, hash); + if (match_index != -1) { + MB_RD_INFO *tx_rd_info = &mb_rd_record->tx_rd_info[match_index]; + fetch_tx_rd_info(n4, tx_rd_info, rd_stats, x); + // Reset the pruning flags. + av1_zero(x->tx_search_prune); + x->tx_split_prune_flag = 0; + return; + } + } + + // If we predict that skip is the optimal RD decision - set the respective + // context and terminate early. + int64_t dist; + + if (cpi->sf.tx_type_search.use_skip_flag_prediction && is_inter && + (!xd->lossless[xd->mi[0]->segment_id]) && + predict_skip_flag(x, bs, &dist, cpi->common.reduced_tx_set_used)) { + // Populate rdstats as per skip decision + set_skip_flag(x, rd_stats, bs, dist); + // Save the RD search results into tx_rd_record. + if (is_mb_rd_hash_enabled) + save_tx_rd_info(n4, hash, x, rd_stats, mb_rd_record); + // Reset the pruning flags. + av1_zero(x->tx_search_prune); + x->tx_split_prune_flag = 0; + return; + } + if (xd->lossless[xd->mi[0]->segment_id]) { choose_smallest_tx_size(cpi, x, rd_stats, ref_best_rd, bs); } else if (cpi->sf.tx_size_search_method == USE_LARGESTALL) { @@ -3788,6 +4060,12 @@ static void super_block_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, } else { choose_tx_size_type_from_rd(cpi, x, rd_stats, ref_best_rd, bs); } + + // Save the RD search results into tx_rd_record. + if (is_mb_rd_hash_enabled) { + assert(mb_rd_record != NULL); + save_tx_rd_info(n4, hash, x, rd_stats, mb_rd_record); + } } // Return the rate cost for luma prediction mode info. of intra blocks. @@ -4564,7 +4842,7 @@ static int64_t rd_pick_intra_sby_mode(const AV1_COMP *const cpi, MACROBLOCK *x, int this_rate, this_rate_tokenonly, s; int64_t this_distortion, this_rd, this_model_rd; mbmi->mode = intra_rd_search_mode_order[mode_idx]; - if (!cpi->oxcf.enable_smooth_intra && + if ((!cpi->oxcf.enable_smooth_intra || cpi->sf.disable_smooth_intra) && (mbmi->mode == SMOOTH_PRED || mbmi->mode == SMOOTH_H_PRED || mbmi->mode == SMOOTH_V_PRED)) continue; @@ -4658,6 +4936,8 @@ static int super_block_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, const TX_SIZE uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd); int plane; int is_cost_valid = 1; + const int is_inter = is_inter_block(mbmi); + int64_t this_rd = 0, skip_rd = 0; av1_init_rd_stats(rd_stats); if (ref_best_rd < 0) is_cost_valid = 0; @@ -4666,7 +4946,7 @@ static int super_block_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, bsize = scale_chroma_bsize(bsize, pd->subsampling_x, pd->subsampling_y); - if (is_inter_block(mbmi) && is_cost_valid) { + if (is_inter && is_cost_valid) { for (plane = 1; plane < MAX_MB_PLANE; ++plane) av1_subtract_plane(x, bsize, plane); } @@ -4674,15 +4954,26 @@ static int super_block_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, if (is_cost_valid) { for (plane = 1; plane < MAX_MB_PLANE; ++plane) { RD_STATS pn_rd_stats; - txfm_rd_in_plane(x, cpi, &pn_rd_stats, ref_best_rd, 0, plane, bsize, - uv_tx_size, cpi->sf.use_fast_coef_costing, FTXS_NONE); + int64_t chroma_ref_best_rd = ref_best_rd; + // For inter blocks, refined ref_best_rd is used for early exit + // For intra blocks, even though current rd crosses ref_best_rd, early + // exit is not recommended as current rd is used for gating subsequent + // modes as well (say, for angular modes) + // TODO(any): Extend the early exit mechanism for intra modes as well + if (cpi->sf.perform_best_rd_based_gating_for_chroma && is_inter && + chroma_ref_best_rd != INT64_MAX) + chroma_ref_best_rd = ref_best_rd - AOMMIN(this_rd, skip_rd); + txfm_rd_in_plane(x, cpi, &pn_rd_stats, chroma_ref_best_rd, 0, plane, + bsize, uv_tx_size, cpi->sf.use_fast_coef_costing, + FTXS_NONE, 0); if (pn_rd_stats.rate == INT_MAX) { is_cost_valid = 0; break; } av1_merge_rd_stats(rd_stats, &pn_rd_stats); - if (RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) > ref_best_rd && - RDCOST(x->rdmult, 0, rd_stats->sse) > ref_best_rd) { + this_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); + skip_rd = RDCOST(x->rdmult, 0, rd_stats->sse); + if (AOMMIN(this_rd, skip_rd) > ref_best_rd) { is_cost_valid = 0; break; } @@ -4730,7 +5021,7 @@ static void tx_type_rd(const AV1_COMP *cpi, MACROBLOCK *x, TX_SIZE tx_size, RD_STATS this_rd_stats; search_txk_type(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, - txb_ctx, ftxs_mode, 0, ref_rdcost, &this_rd_stats); + txb_ctx, ftxs_mode, 0, 0, ref_rdcost, &this_rd_stats); av1_merge_rd_stats(rd_stats, &this_rd_stats); @@ -4928,13 +5219,6 @@ static void try_tx_block_no_split( const int txk_type_idx = av1_get_txk_type_index(plane_bsize, blk_row, blk_col); no_split->tx_type = mbmi->txk_type[txk_type_idx]; - -#if CONFIG_ONE_PASS_SVM - if (plane_bsize >= BLOCK_8X8) { - av1_add_reg_stat(rd_stats, p->eobs[block], no_split->rd, rd_stats->sse, - blk_row, blk_col, plane_bsize, txsize_to_bsize[tx_size]); - } -#endif } static void select_tx_block(const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, @@ -5175,9 +5459,6 @@ static int64_t select_tx_size_and_type(const AV1_COMP *cpi, MACROBLOCK *x, if (skip_rd <= this_rd) { rd_stats->skip = 1; -#if CONFIG_ONE_PASS_SVM - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); -#endif } else { rd_stats->skip = 0; } @@ -5195,11 +5476,6 @@ static int64_t select_tx_size_and_type(const AV1_COMP *cpi, MACROBLOCK *x, int64_t rd; if (rd_stats->skip) { rd = RDCOST(x->rdmult, s1, rd_stats->sse); -#if CONFIG_ONE_PASS_SVM - // TODO(chiyotsai@google.com): Investigate if these updates are really - // needed. - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); -#endif } else { rd = RDCOST(x->rdmult, rd_stats->rate + s0, rd_stats->dist); if (!xd->lossless[xd->mi[0]->segment_id]) @@ -5258,20 +5534,9 @@ static void tx_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, x->plane[0].txb_entropy_ctx[block] = 0; update_txk_array(mbmi->txk_type, plane_bsize, blk_row, blk_col, tx_size, DCT_DCT); -#if CONFIG_ONE_PASS_SVM - av1_add_reg_stat(rd_stats, 0, RDCOST(x->rdmult, 0, rd_stats->sse), - rd_stats->sse, blk_row, blk_col, plane_bsize, - txsize_to_bsize[tx_size]); -#endif } else { rd_stats->skip = 0; set_blk_skip(x, 0, blk_row * mi_width + blk_col, 0); -#if CONFIG_ONE_PASS_SVM - av1_add_reg_stat(rd_stats, x->plane[0].eobs[block], - RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist), - rd_stats->sse, blk_row, blk_col, plane_bsize, - txsize_to_bsize[tx_size]); -#endif } if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) rd_stats->rate += x->txfm_partition_cost[ctx][0]; @@ -5379,11 +5644,6 @@ static int inter_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, rd_stats->rate = 0; rd_stats->dist = rd_stats->sse; rd_stats->skip = 1; -#if CONFIG_ONE_PASS_SVM - // TODO(chiyotasi@google.com): Investigate if these updates are really - // needed. - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); -#endif } if (this_rd > ref_best_rd) is_cost_valid = 0; @@ -5394,52 +5654,6 @@ static int inter_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, return is_cost_valid; } -static INLINE uint32_t get_block_residue_hash(MACROBLOCK *x, BLOCK_SIZE bsize) { - const int rows = block_size_high[bsize]; - const int cols = block_size_wide[bsize]; - const int16_t *diff = x->plane[0].src_diff; - const uint32_t hash = av1_get_crc32c_value(&x->mb_rd_record.crc_calculator, - (uint8_t *)diff, 2 * rows * cols); - return (hash << 5) + bsize; -} - -static void save_tx_rd_info(int n4, uint32_t hash, const MACROBLOCK *const x, - const RD_STATS *const rd_stats, - MB_RD_RECORD *tx_rd_record) { - int index; - if (tx_rd_record->num < RD_RECORD_BUFFER_LEN) { - index = - (tx_rd_record->index_start + tx_rd_record->num) % RD_RECORD_BUFFER_LEN; - ++tx_rd_record->num; - } else { - index = tx_rd_record->index_start; - tx_rd_record->index_start = - (tx_rd_record->index_start + 1) % RD_RECORD_BUFFER_LEN; - } - MB_RD_INFO *const tx_rd_info = &tx_rd_record->tx_rd_info[index]; - const MACROBLOCKD *const xd = &x->e_mbd; - const MB_MODE_INFO *const mbmi = xd->mi[0]; - tx_rd_info->hash_value = hash; - tx_rd_info->tx_size = mbmi->tx_size; - memcpy(tx_rd_info->blk_skip, x->blk_skip, - sizeof(tx_rd_info->blk_skip[0]) * n4); - av1_copy(tx_rd_info->inter_tx_size, mbmi->inter_tx_size); - av1_copy(tx_rd_info->txk_type, mbmi->txk_type); - tx_rd_info->rd_stats = *rd_stats; -} - -static void fetch_tx_rd_info(int n4, const MB_RD_INFO *const tx_rd_info, - RD_STATS *const rd_stats, MACROBLOCK *const x) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - mbmi->tx_size = tx_rd_info->tx_size; - memcpy(x->blk_skip, tx_rd_info->blk_skip, - sizeof(tx_rd_info->blk_skip[0]) * n4); - av1_copy(mbmi->inter_tx_size, tx_rd_info->inter_tx_size); - av1_copy(mbmi->txk_type, tx_rd_info->txk_type); - *rd_stats = tx_rd_info->rd_stats; -} - static int find_tx_size_rd_info(TXB_RD_RECORD *cur_record, const uint32_t hash) { // Linear search through the circular buffer to find matching hash. @@ -5690,164 +5904,6 @@ static int find_tx_size_rd_records(MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row, return 1; } -// origin_threshold * 128 / 100 -static const uint32_t skip_pred_threshold[3][BLOCK_SIZES_ALL] = { - { - 64, 64, 64, 70, 60, 60, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 64, 64, 70, 70, 68, 68, - }, - { - 88, 88, 88, 86, 87, 87, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 88, 88, 86, 86, 68, 68, - }, - { - 90, 93, 93, 90, 93, 93, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 90, 90, 90, 90, 74, 74, - }, -}; - -// lookup table for predict_skip_flag -// int max_tx_size = max_txsize_rect_lookup[bsize]; -// if (tx_size_high[max_tx_size] > 16 || tx_size_wide[max_tx_size] > 16) -// max_tx_size = AOMMIN(max_txsize_lookup[bsize], TX_16X16); -static const TX_SIZE max_predict_sf_tx_size[BLOCK_SIZES_ALL] = { - TX_4X4, TX_4X8, TX_8X4, TX_8X8, TX_8X16, TX_16X8, - TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_16X16, - TX_16X16, TX_16X16, TX_16X16, TX_16X16, TX_4X16, TX_16X4, - TX_8X8, TX_8X8, TX_16X16, TX_16X16, -}; - -// Uses simple features on top of DCT coefficients to quickly predict -// whether optimal RD decision is to skip encoding the residual. -// The sse value is stored in dist. -static int predict_skip_flag(MACROBLOCK *x, BLOCK_SIZE bsize, int64_t *dist, - int reduced_tx_set) { - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const MACROBLOCKD *xd = &x->e_mbd; - const int16_t dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd); - - *dist = pixel_diff_dist(x, 0, 0, 0, bsize, bsize, NULL); - - const int64_t mse = *dist / bw / bh; - // Normalized quantizer takes the transform upscaling factor (8 for tx size - // smaller than 32) into account. - const int16_t normalized_dc_q = dc_q >> 3; - const int64_t mse_thresh = (int64_t)normalized_dc_q * normalized_dc_q / 8; - // Predict not to skip when mse is larger than threshold. - if (mse > mse_thresh) return 0; - - const int max_tx_size = max_predict_sf_tx_size[bsize]; - const int tx_h = tx_size_high[max_tx_size]; - const int tx_w = tx_size_wide[max_tx_size]; - DECLARE_ALIGNED(32, tran_low_t, coefs[32 * 32]); - TxfmParam param; - param.tx_type = DCT_DCT; - param.tx_size = max_tx_size; - param.bd = xd->bd; - param.is_hbd = is_cur_buf_hbd(xd); - param.lossless = 0; - param.tx_set_type = av1_get_ext_tx_set_type( - param.tx_size, is_inter_block(xd->mi[0]), reduced_tx_set); - const int bd_idx = (xd->bd == 8) ? 0 : ((xd->bd == 10) ? 1 : 2); - const uint32_t max_qcoef_thresh = skip_pred_threshold[bd_idx][bsize]; - const int16_t *src_diff = x->plane[0].src_diff; - const int n_coeff = tx_w * tx_h; - const int16_t ac_q = av1_ac_quant_QTX(x->qindex, 0, xd->bd); - const uint32_t dc_thresh = max_qcoef_thresh * dc_q; - const uint32_t ac_thresh = max_qcoef_thresh * ac_q; - for (int row = 0; row < bh; row += tx_h) { - for (int col = 0; col < bw; col += tx_w) { - av1_fwd_txfm(src_diff + col, coefs, bw, ¶m); - // Operating on TX domain, not pixels; we want the QTX quantizers - const uint32_t dc_coef = (((uint32_t)abs(coefs[0])) << 7); - if (dc_coef >= dc_thresh) return 0; - for (int i = 1; i < n_coeff; ++i) { - const uint32_t ac_coef = (((uint32_t)abs(coefs[i])) << 7); - if (ac_coef >= ac_thresh) return 0; - } - } - src_diff += tx_h * bw; - } - return 1; -} - -#if CONFIG_ONE_PASS_SVM -static void calc_regional_sse(MACROBLOCK *x, BLOCK_SIZE bsize, int64_t dist, - RD_STATS *rd_stats) { - // TODO(chiyotsai@google.com): Don't need regional sse's unless we are doing - // none. - const int bw = block_size_wide[bsize]; - const int bw_mi = bw >> tx_size_wide_log2[0]; - const int bh_mi = bw >> tx_size_high_log2[0]; - const BLOCK_SIZE split_size = get_partition_subsize(bsize, PARTITION_SPLIT); - int64_t dist_0, dist_1, dist_2, dist_3; - MACROBLOCKD *xd = &x->e_mbd; - dist_0 = pixel_diff_dist(x, AOM_PLANE_Y, 0, 0, bsize, split_size, NULL); - dist_1 = - pixel_diff_dist(x, AOM_PLANE_Y, 0, bw_mi / 2, bsize, split_size, NULL); - dist_2 = - pixel_diff_dist(x, AOM_PLANE_Y, bh_mi / 2, 0, bsize, split_size, NULL); - dist_3 = pixel_diff_dist(x, AOM_PLANE_Y, bh_mi / 2, bw_mi / 2, bsize, - split_size, NULL); - - if (is_cur_buf_hbd(xd)) { - dist = ROUND_POWER_OF_TWO(dist, (xd->bd - 8) * 2); - dist_0 = ROUND_POWER_OF_TWO(dist_0, (xd->bd - 8) * 2); - dist_1 = ROUND_POWER_OF_TWO(dist_1, (xd->bd - 8) * 2); - dist_2 = ROUND_POWER_OF_TWO(dist_2, (xd->bd - 8) * 2); - dist_3 = ROUND_POWER_OF_TWO(dist_3, (xd->bd - 8) * 2); - } - const int scaling_factor = MAX_MIB_SIZE * MAX_MIB_SIZE; - rd_stats->y_sse = (dist << 4); - rd_stats->sse_0 = (dist_0 << 4) * scaling_factor; - rd_stats->sse_1 = (dist_1 << 4) * scaling_factor; - rd_stats->sse_2 = (dist_2 << 4) * scaling_factor; - rd_stats->sse_3 = (dist_3 << 4) * scaling_factor; - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); -} -#endif - -// Used to set proper context for early termination with skip = 1. -static void set_skip_flag(MACROBLOCK *x, RD_STATS *rd_stats, int bsize, - int64_t dist) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int n4 = bsize_to_num_blk(bsize); - const TX_SIZE tx_size = max_txsize_rect_lookup[bsize]; - memset(mbmi->txk_type, DCT_DCT, sizeof(mbmi->txk_type[0]) * TXK_TYPE_BUF_LEN); - memset(mbmi->inter_tx_size, tx_size, sizeof(mbmi->inter_tx_size)); - mbmi->tx_size = tx_size; - for (int i = 0; i < n4; ++i) set_blk_skip(x, 0, i, 1); - rd_stats->skip = 1; - if (is_cur_buf_hbd(xd)) dist = ROUND_POWER_OF_TWO(dist, (xd->bd - 8) * 2); - rd_stats->dist = rd_stats->sse = (dist << 4); - // Though decision is to make the block as skip based on luma stats, - // it is possible that block becomes non skip after chroma rd. In addition - // intermediate non skip costs calculated by caller function will be - // incorrect, if rate is set as zero (i.e., if zero_blk_rate is not - // accounted). Hence intermediate rate is populated to code the luma tx blks - // as skip, the caller function based on final rd decision (i.e., skip vs - // non-skip) sets the final rate accordingly. Here the rate populated - // corresponds to coding all the tx blocks with zero_blk_rate (based on max tx - // size possible) in the current block. Eg: For 128*128 block, rate would be - // 4 * zero_blk_rate where zero_blk_rate corresponds to coding of one 64x64 tx - // block as 'all zeros' - ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE]; - ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE]; - av1_get_entropy_contexts(bsize, &xd->plane[0], ctxa, ctxl); - ENTROPY_CONTEXT *ta = ctxa; - ENTROPY_CONTEXT *tl = ctxl; - const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); - TXB_CTX txb_ctx; - get_txb_ctx(bsize, tx_size, 0, ta, tl, &txb_ctx); - const int zero_blk_rate = x->coeff_costs[txs_ctx][PLANE_TYPE_Y] - .txb_skip_cost[txb_ctx.txb_skip_ctx][1]; - rd_stats->rate = zero_blk_rate * - (block_size_wide[bsize] >> tx_size_wide_log2[tx_size]) * - (block_size_high[bsize] >> tx_size_high_log2[tx_size]); -} - // Search for best transform size and type for luma inter blocks. static void pick_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_stats, BLOCK_SIZE bsize, @@ -5880,6 +5936,7 @@ static void pick_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, } uint32_t hash = 0; + int32_t match_index = -1; MB_RD_RECORD *mb_rd_record = NULL; const int within_border = mi_row >= xd->tile.mi_row_start && @@ -5891,18 +5948,11 @@ static void pick_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, if (is_mb_rd_hash_enabled) { hash = get_block_residue_hash(x, bsize); mb_rd_record = &x->mb_rd_record; - if (ref_best_rd != INT64_MAX) { - for (int i = 0; i < mb_rd_record->num; ++i) { - const int index = - (mb_rd_record->index_start + i) % RD_RECORD_BUFFER_LEN; - // If there is a match in the tx_rd_record, fetch the RD decision and - // terminate early. - if (mb_rd_record->tx_rd_info[index].hash_value == hash) { - MB_RD_INFO *tx_rd_info = &mb_rd_record->tx_rd_info[index]; - fetch_tx_rd_info(n4, tx_rd_info, rd_stats, x); - return; - } - } + match_index = find_mb_rd_info(mb_rd_record, ref_best_rd, hash); + if (match_index != -1) { + MB_RD_INFO *tx_rd_info = &mb_rd_record->tx_rd_info[match_index]; + fetch_tx_rd_info(n4, tx_rd_info, rd_stats, x); + return; } } @@ -5912,12 +5962,6 @@ static void pick_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, if (cpi->sf.tx_type_search.use_skip_flag_prediction && predict_skip_flag(x, bsize, &dist, cm->reduced_tx_set_used)) { set_skip_flag(x, rd_stats, bsize, dist); -#if CONFIG_ONE_PASS_SVM - if (bsize >= BLOCK_8X8 && mi_size_wide[bsize] == mi_size_high[bsize] && - xd->mi[0]->partition == PARTITION_NONE) { - calc_regional_sse(x, bsize, dist, rd_stats); - } -#endif // Save the RD search results into tx_rd_record. if (is_mb_rd_hash_enabled) save_tx_rd_info(n4, hash, x, rd_stats, mb_rd_record); @@ -6319,7 +6363,7 @@ static int cfl_rd_pick_alpha(MACROBLOCK *const x, const AV1_COMP *const cpi, mbmi->cfl_alpha_idx = 0; mbmi->cfl_alpha_signs = joint_sign; txfm_rd_in_plane(x, cpi, &rd_stats, best_rd, 0, plane + 1, bsize, - tx_size, cpi->sf.use_fast_coef_costing, FTXS_NONE); + tx_size, cpi->sf.use_fast_coef_costing, FTXS_NONE, 0); if (rd_stats.rate == INT_MAX) break; } const int alpha_rate = x->cfl_cost[joint_sign][plane][0]; @@ -6347,7 +6391,8 @@ static int cfl_rd_pick_alpha(MACROBLOCK *const x, const AV1_COMP *const cpi, mbmi->cfl_alpha_idx = (c << CFL_ALPHABET_SIZE_LOG2) + c; mbmi->cfl_alpha_signs = joint_sign; txfm_rd_in_plane(x, cpi, &rd_stats, best_rd, 0, plane + 1, bsize, - tx_size, cpi->sf.use_fast_coef_costing, FTXS_NONE); + tx_size, cpi->sf.use_fast_coef_costing, FTXS_NONE, + 0); if (rd_stats.rate == INT_MAX) break; } const int alpha_rate = x->cfl_cost[joint_sign][plane][c]; @@ -6420,6 +6465,11 @@ static int64_t rd_pick_intra_sbuv_mode(const AV1_COMP *const cpi, MACROBLOCK *x, if (!(cpi->sf.intra_uv_mode_mask[txsize_sqr_up_map[max_tx_size]] & (1 << mode))) continue; + if (!cpi->oxcf.enable_smooth_intra && mode >= UV_SMOOTH_PRED && + mode <= UV_SMOOTH_H_PRED) + continue; + + if (!cpi->oxcf.enable_paeth_intra && mode == UV_PAETH_PRED) continue; mbmi->uv_mode = mode; int cfl_alpha_rate = 0; @@ -6572,35 +6622,6 @@ static int get_interinter_compound_mask_rate(const MACROBLOCK *const x, } } -typedef struct { - int eobs; - int brate; - int byrate; - int64_t bdist; - int64_t bsse; - int64_t brdcost; - int_mv mvs[2]; - int_mv pred_mv[2]; - int_mv ref_mv[2]; - - ENTROPY_CONTEXT ta[2]; - ENTROPY_CONTEXT tl[2]; -} SEG_RDSTAT; - -typedef struct { - int_mv *ref_mv[2]; - int_mv mvp; - - int64_t segment_rd; - int r; - int64_t d; - int64_t sse; - int segment_yrate; - PREDICTION_MODE modes[4]; - SEG_RDSTAT rdstat[4][INTER_MODES + INTER_COMPOUND_MODES]; - int mvthresh; -} BEST_SEG_INFO; - static INLINE int mv_check_bounds(const MvLimits *mv_limits, const MV *mv) { return (mv->row >> 3) < mv_limits->row_min || (mv->row >> 3) > mv_limits->row_max || @@ -7131,13 +7152,13 @@ static void single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x, bestsme = av1_full_pixel_search( cpi, x, bsize, &mvp_full, step_param, cpi->sf.mv.search_method, 0, sadpb, cond_cost_list(cpi, cost_list), &ref_mv, INT_MAX, 1, - (MI_SIZE * mi_col), (MI_SIZE * mi_row), 0); + (MI_SIZE * mi_col), (MI_SIZE * mi_row), 0, &cpi->ss_cfg[SS_CFG_SRC]); break; case OBMC_CAUSAL: - bestsme = av1_obmc_full_pixel_search(cpi, x, &mvp_full, step_param, sadpb, - MAX_MVSEARCH_STEPS - 1 - step_param, - 1, &cpi->fn_ptr[bsize], &ref_mv, - &(x->best_mv.as_mv), 0); + bestsme = av1_obmc_full_pixel_search( + cpi, x, &mvp_full, step_param, sadpb, + MAX_MVSEARCH_STEPS - 1 - step_param, 1, &cpi->fn_ptr[bsize], &ref_mv, + &(x->best_mv.as_mv), 0, &cpi->ss_cfg[SS_CFG_SRC]); break; default: assert(0 && "Invalid motion mode!\n"); } @@ -7872,13 +7893,17 @@ static int64_t build_and_cost_compound_type( int rate_mv, const BUFFER_SET *ctx, int *out_rate_mv, uint8_t **preds0, uint8_t **preds1, int16_t *residual1, int16_t *diff10, int *strides, int mi_row, int mi_col, int mode_rate, int64_t ref_best_rd, - int *calc_pred_masked_compound, int32_t *comp_rate, int64_t *comp_dist) { + int *calc_pred_masked_compound, int32_t *comp_rate, int64_t *comp_dist, + int64_t *const comp_model_rd, const int64_t comp_best_model_rd, + int64_t *const comp_model_rd_cur) { const AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; int64_t best_rd_cur = INT64_MAX; int64_t rd = INT64_MAX; const COMPOUND_TYPE compound_type = mbmi->interinter_comp.type; + int rate_sum, tmp_skip_txfm_sb; + int64_t dist_sum, tmp_skip_sse_sb; // TODO(any): Save pred and mask calculation as well into records. However // this may increase memory requirements as compound segment mask needs to be @@ -7898,8 +7923,10 @@ static int64_t build_and_cost_compound_type( const unsigned int mse = ROUND_POWER_OF_TWO(sse, num_pels_log2_lookup[bsize]); // If two predictors are very similar, skip wedge compound mode search - if (mse < 8 || (!have_newmv_in_inter_mode(this_mode) && mse < 64)) + if (mse < 8 || (!have_newmv_in_inter_mode(this_mode) && mse < 64)) { + *comp_model_rd_cur = INT64_MAX; return INT64_MAX; + } } best_rd_cur = @@ -7911,7 +7938,10 @@ static int64_t build_and_cost_compound_type( // is unlikely to be the best mode considering the transform rd cost and other // mode overhead cost int64_t mode_rd = RDCOST(x->rdmult, *rs2 + mode_rate, 0); - if (mode_rd > ref_best_rd) return INT64_MAX; + if (mode_rd > ref_best_rd) { + *comp_model_rd_cur = INT64_MAX; + return INT64_MAX; + } // Reuse data if matching record is found if (comp_rate[compound_type] == INT_MAX) { @@ -7922,42 +7952,61 @@ static int64_t build_and_cost_compound_type( cpi, x, cur_mv, bsize, this_mode, mi_row, mi_col); av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, ctx, bsize, AOM_PLANE_Y, AOM_PLANE_Y); - int rate_sum, tmp_skip_txfm_sb; - int64_t dist_sum, tmp_skip_sse_sb; + model_rd_sb_fn[MODELRD_TYPE_MASKED_COMPOUND]( cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &rate_sum, &dist_sum, &tmp_skip_txfm_sb, &tmp_skip_sse_sb, NULL, NULL, NULL); rd = RDCOST(x->rdmult, *rs2 + *out_rate_mv + rate_sum, dist_sum); + *comp_model_rd_cur = rd; if (rd >= best_rd_cur) { mbmi->mv[0].as_int = cur_mv[0].as_int; mbmi->mv[1].as_int = cur_mv[1].as_int; *out_rate_mv = rate_mv; av1_build_wedge_inter_predictor_from_buf(xd, bsize, 0, 0, preds0, strides, preds1, strides); + *comp_model_rd_cur = best_rd_cur; } } else { *out_rate_mv = rate_mv; av1_build_wedge_inter_predictor_from_buf(xd, bsize, 0, 0, preds0, strides, preds1, strides); + model_rd_sb_fn[MODELRD_TYPE_MASKED_COMPOUND]( + cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &rate_sum, &dist_sum, + &tmp_skip_txfm_sb, &tmp_skip_sse_sb, NULL, NULL, NULL); + *comp_model_rd_cur = + RDCOST(x->rdmult, *rs2 + *out_rate_mv + rate_sum, dist_sum); } RD_STATS rd_stats; - rd = estimate_yrd_for_sb(cpi, bsize, x, INT64_MAX, &rd_stats); + + if (cpi->sf.prune_comp_type_by_model_rd && + (*comp_model_rd_cur > comp_best_model_rd) && + comp_best_model_rd != INT64_MAX) { + *comp_model_rd_cur = INT64_MAX; + return INT64_MAX; + } + rd = estimate_yrd_for_sb(cpi, bsize, x, ref_best_rd, &rd_stats); if (rd != INT64_MAX) { rd = RDCOST(x->rdmult, *rs2 + *out_rate_mv + rd_stats.rate, rd_stats.dist); // Backup rate and distortion for future reuse comp_rate[compound_type] = rd_stats.rate; comp_dist[compound_type] = rd_stats.dist; + comp_model_rd[compound_type] = *comp_model_rd_cur; } } else { assert(comp_dist[compound_type] != INT64_MAX); - // Rate is populated assuming no refinement is done=> not NEWMV case - assert(!have_newmv_in_inter_mode(this_mode)); + // When disable_interinter_wedge_newmv_search is set, motion refinement is + // disabled. Hence rate and distortion can be reused in this case as well + assert(IMPLIES(have_newmv_in_inter_mode(this_mode), + cpi->sf.disable_interinter_wedge_newmv_search)); + assert(mbmi->mv[0].as_int == cur_mv[0].as_int); + assert(mbmi->mv[1].as_int == cur_mv[1].as_int); *out_rate_mv = rate_mv; // Calculate RD cost based on stored stats rd = RDCOST(x->rdmult, *rs2 + *out_rate_mv + comp_rate[compound_type], comp_dist[compound_type]); + *comp_model_rd_cur = comp_model_rd[compound_type]; } return rd; } @@ -8328,12 +8377,51 @@ static INLINE void find_best_non_dual_interp_filter( const int switchable_ctx[2], const int skip_ver, const int skip_hor, int *rate, int64_t *dist, int filter_set_size) { int16_t i; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; // Regular filter evaluation should have been done and hence the same should // be the winner assert(x->e_mbd.mi[0]->interp_filters == filter_sets[0]); assert(filter_set_size == DUAL_FILTER_SET_SIZE); - + if ((skip_hor & skip_ver) != cpi->default_interp_skip_flags) { + const AV1_COMMON *cm = &cpi->common; + int bsl, pred_filter_search; + InterpFilters af = SWITCHABLE, lf = SWITCHABLE, filter_idx = 0; + const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; + const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; + bsl = mi_size_wide_log2[bsize]; + pred_filter_search = + cpi->sf.cb_pred_filter_search + ? (((mi_row + mi_col) >> bsl) + + get_chessboard_index(cm->current_frame.frame_number)) & + 0x1 + : 0; + if (above_mbmi && is_inter_block(above_mbmi)) { + af = above_mbmi->interp_filters; + } + if (left_mbmi && is_inter_block(left_mbmi)) { + lf = left_mbmi->interp_filters; + } + pred_filter_search &= ((af == lf) && (af != SWITCHABLE)); + if (pred_filter_search) { + filter_idx = SWITCHABLE * (af & 0xf); + // This assert tells that (filter_x == filter_y) for non-dual filter case + assert((filter_sets[filter_idx] & 0xffff) == + (filter_sets[filter_idx] >> 16)); + if (cpi->sf.adaptive_interp_filter_search && + (cpi->sf.interp_filter_search_mask & (1 << (filter_idx >> 2)))) { + return; + } + if (filter_idx) { + interpolation_filter_rd( + x, cpi, tile_data, bsize, mi_row, mi_col, orig_dst, rd, + switchable_rate, skip_txfm_sb, skip_sse_sb, dst_bufs, filter_idx, + switchable_ctx, (skip_hor & skip_ver), rate, dist); + } + return; + } + } // Reuse regular filter's modeled rd data for sharp filter for following // cases // 1) When bsize is 4x4 @@ -8384,8 +8472,6 @@ static INLINE void find_best_non_dual_interp_filter( // accounting switchable filter rate) if (cpi->sf.skip_sharp_interp_filter_search && skip_pred != cpi->default_interp_skip_flags) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; if (mbmi->interp_filters == filter_sets[(SWITCHABLE_FILTERS + 1)]) break; } @@ -8407,10 +8493,12 @@ static INLINE int is_interp_filter_match(const INTERPOLATION_FILTER_STATS *st, } // Checks if characteristics of search match -static INLINE int is_comp_rd_match(const MACROBLOCK *const x, +static INLINE int is_comp_rd_match(const AV1_COMP *const cpi, + const MACROBLOCK *const x, const COMP_RD_STATS *st, const MB_MODE_INFO *const mi, - int32_t *comp_rate, int64_t *comp_dist) { + int32_t *comp_rate, int64_t *comp_dist, + int64_t *comp_model_rd) { // TODO(ranjit): Ensure that compound type search use regular filter always // and check if following check can be removed // Check if interp filter matches with previous case @@ -8428,20 +8516,25 @@ static INLINE int is_comp_rd_match(const MACROBLOCK *const x, } // Store the stats for compound average - comp_rate[0] = st->rate[0]; - comp_dist[0] = st->dist[0]; + comp_rate[COMPOUND_AVERAGE] = st->rate[COMPOUND_AVERAGE]; + comp_dist[COMPOUND_AVERAGE] = st->dist[COMPOUND_AVERAGE]; + comp_model_rd[COMPOUND_AVERAGE] = st->comp_model_rd[COMPOUND_AVERAGE]; + comp_rate[COMPOUND_DISTWTD] = st->rate[COMPOUND_DISTWTD]; + comp_dist[COMPOUND_DISTWTD] = st->dist[COMPOUND_DISTWTD]; + comp_model_rd[COMPOUND_DISTWTD] = st->comp_model_rd[COMPOUND_DISTWTD]; // For compound wedge/segment, reuse data only if NEWMV is not present in // either of the directions - if (!have_newmv_in_inter_mode(mi->mode) && - !have_newmv_in_inter_mode(st->mode)) { - memcpy(&comp_rate[1], &st->rate[1], sizeof(comp_rate[1]) * 2); - memcpy(&comp_dist[1], &st->dist[1], sizeof(comp_dist[1]) * 2); + if ((!have_newmv_in_inter_mode(mi->mode) && + !have_newmv_in_inter_mode(st->mode)) || + (cpi->sf.disable_interinter_wedge_newmv_search)) { + memcpy(&comp_rate[COMPOUND_WEDGE], &st->rate[COMPOUND_WEDGE], + sizeof(comp_rate[COMPOUND_WEDGE]) * 2); + memcpy(&comp_dist[COMPOUND_WEDGE], &st->dist[COMPOUND_WEDGE], + sizeof(comp_dist[COMPOUND_WEDGE]) * 2); + memcpy(&comp_model_rd[COMPOUND_WEDGE], &st->comp_model_rd[COMPOUND_WEDGE], + sizeof(comp_model_rd[COMPOUND_WEDGE]) * 2); } - - // TODO(ranjit) : Check if compound wedge/segment can reuse data for NEWMV - // case as well based on speed feature - return 1; } @@ -8460,12 +8553,14 @@ static INLINE int find_interp_filter_in_stats(MACROBLOCK *x, } // Checks if similar compound type search case is accounted earlier // If found, returns relevant rd data -static INLINE int find_comp_rd_in_stats(const MACROBLOCK *x, +static INLINE int find_comp_rd_in_stats(const AV1_COMP *const cpi, + const MACROBLOCK *x, const MB_MODE_INFO *const mbmi, - int32_t *comp_rate, - int64_t *comp_dist) { + int32_t *comp_rate, int64_t *comp_dist, + int64_t *comp_model_rd) { for (int j = 0; j < x->comp_rd_stats_idx; ++j) { - if (is_comp_rd_match(x, &x->comp_rd_stats[j], mbmi, comp_rate, comp_dist)) { + if (is_comp_rd_match(cpi, x, &x->comp_rd_stats[j], mbmi, comp_rate, + comp_dist, comp_model_rd)) { return 1; } } @@ -8473,7 +8568,10 @@ static INLINE int find_comp_rd_in_stats(const MACROBLOCK *x, } static INLINE void save_interp_filter_search_stat(MACROBLOCK *x, - MB_MODE_INFO *const mbmi) { + MB_MODE_INFO *const mbmi, + int64_t rd, int skip_txfm_sb, + int64_t skip_sse_sb, + unsigned int pred_sse) { const int comp_idx = mbmi->compound_idx; const int offset = x->interp_filter_stats_idx[comp_idx]; if (offset < MAX_INTERP_FILTER_STATS) { @@ -8481,7 +8579,11 @@ static INLINE void save_interp_filter_search_stat(MACROBLOCK *x, { mbmi->mv[0], mbmi->mv[1] }, { mbmi->ref_frame[0], mbmi->ref_frame[1] }, - mbmi->interinter_comp.type }; + mbmi->interinter_comp.type, + rd, + skip_txfm_sb, + skip_sse_sb, + pred_sse }; x->interp_filter_stats[comp_idx][offset] = stat; x->interp_filter_stats_idx[comp_idx]++; } @@ -8491,12 +8593,15 @@ static INLINE void save_comp_rd_search_stat(MACROBLOCK *x, const MB_MODE_INFO *const mbmi, const int32_t *comp_rate, const int64_t *comp_dist, + const int64_t *comp_model_rd, const int_mv *cur_mv) { const int offset = x->comp_rd_stats_idx; if (offset < MAX_COMP_RD_STATS) { COMP_RD_STATS *const rd_stats = x->comp_rd_stats + offset; memcpy(rd_stats->rate, comp_rate, sizeof(rd_stats->rate)); memcpy(rd_stats->dist, comp_dist, sizeof(rd_stats->dist)); + memcpy(rd_stats->comp_model_rd, comp_model_rd, + sizeof(rd_stats->comp_model_rd)); memcpy(rd_stats->mv, cur_mv, sizeof(rd_stats->mv)); memcpy(rd_stats->ref_frames, mbmi->ref_frame, sizeof(rd_stats->ref_frames)); rd_stats->mode = mbmi->mode; @@ -8518,8 +8623,8 @@ static int64_t interpolation_filter_search( const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst, InterpFilter (*const single_filter)[REF_FRAMES], int64_t *const rd, int *const switchable_rate, int *const skip_txfm_sb, - int64_t *const skip_sse_sb, const int skip_build_pred, - HandleInterModeArgs *args, int64_t ref_best_rd) { + int64_t *const skip_sse_sb, int *skip_build_pred, HandleInterModeArgs *args, + int64_t ref_best_rd) { const AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); MACROBLOCKD *const xd = &x->e_mbd; @@ -8536,12 +8641,23 @@ static int64_t interpolation_filter_search( const int ref_frame = xd->mi[0]->ref_frame[0]; (void)single_filter; - int match_found = -1; + int match_found_idx = -1; const InterpFilter assign_filter = cm->interp_filter; if (cpi->sf.skip_repeat_interpolation_filter_search && need_search) { - match_found = find_interp_filter_in_stats(x, mbmi); + match_found_idx = find_interp_filter_in_stats(x, mbmi); } - if (!need_search || match_found == -1) { + if (match_found_idx != -1) { + const int comp_idx = mbmi->compound_idx; + *rd = x->interp_filter_stats[comp_idx][match_found_idx].rd; + *skip_txfm_sb = + x->interp_filter_stats[comp_idx][match_found_idx].skip_txfm_sb; + *skip_sse_sb = + x->interp_filter_stats[comp_idx][match_found_idx].skip_sse_sb; + x->pred_sse[ref_frame] = + x->interp_filter_stats[comp_idx][match_found_idx].pred_sse; + return 0; + } + if (!need_search || match_found_idx == -1) { set_default_interp_filters(mbmi, assign_filter); } int switchable_ctx[2]; @@ -8549,9 +8665,10 @@ static int64_t interpolation_filter_search( switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1); *switchable_rate = get_switchable_rate(x, mbmi->interp_filters, switchable_ctx); - if (!skip_build_pred) { + if (!(*skip_build_pred)) { av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, 0, av1_num_planes(cm) - 1); + *skip_build_pred = 1; } #if CONFIG_COLLECT_RD_STATS == 3 @@ -8578,7 +8695,7 @@ static int64_t interpolation_filter_search( *skip_sse_sb = best_skip_sse_sb[1]; x->pred_sse[ref_frame] = (unsigned int)(best_skip_sse_sb[0] >> 4); - if (assign_filter != SWITCHABLE || match_found != -1) { + if (assign_filter != SWITCHABLE || match_found_idx != -1) { return 0; } if (!need_search) { @@ -8748,8 +8865,9 @@ static int64_t interpolation_filter_search( // save search results if (cpi->sf.skip_repeat_interpolation_filter_search) { - assert(match_found == -1); - save_interp_filter_search_stat(x, mbmi); + assert(match_found_idx == -1); + save_interp_filter_search_stat(x, mbmi, *rd, *skip_txfm_sb, *skip_sse_sb, + x->pred_sse[ref_frame]); } return 0; } @@ -8836,8 +8954,15 @@ static int txfm_search(const AV1_COMP *cpi, const TileDataEnc *tile_data, av1_init_rd_stats(rd_stats_uv); const int num_planes = av1_num_planes(cm); if (num_planes > 1) { + int64_t ref_best_chroma_rd = ref_best_rd; + // Calculate best rd cost possible for chroma + if (cpi->sf.perform_best_rd_based_gating_for_chroma && + (ref_best_chroma_rd != INT64_MAX)) { + ref_best_chroma_rd = + (ref_best_chroma_rd - AOMMIN(non_skip_rdcosty, skip_rdcosty)); + } const int is_cost_valid_uv = - super_block_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_rd); + super_block_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_chroma_rd); if (!is_cost_valid_uv) { mbmi->ref_frame[1] = ref_frame_1; return 0; @@ -8861,9 +8986,6 @@ static int txfm_search(const AV1_COMP *cpi, const TileDataEnc *tile_data, mbmi->ref_frame[1] = ref_frame_1; return 0; } -#if CONFIG_ONE_PASS_SVM - av1_reg_stat_skipmode_update(rd_stats_y, x->rdmult); -#endif } else if (!xd->lossless[mbmi->segment_id] && (RDCOST(x->rdmult, rd_stats_y->rate + rd_stats_uv->rate + skip_flag_cost[0], @@ -8877,9 +8999,6 @@ static int txfm_search(const AV1_COMP *cpi, const TileDataEnc *tile_data, rd_stats_y->rate = 0; rd_stats_uv->rate = 0; mbmi->skip = 1; -#if CONFIG_ONE_PASS_SVM - av1_reg_stat_skipmode_update(rd_stats_y, x->rdmult); -#endif } else { rd_stats->rate += skip_flag_cost[0]; mbmi->skip = 0; @@ -8945,13 +9064,14 @@ static int handle_inter_intra_mode(const AV1_COMP *const cpi, mbmi->ref_frame[1] = INTRA_FRAME; best_interintra_mode = args->inter_intra_mode[mbmi->ref_frame[0]]; - if (cpi->oxcf.enable_smooth_interintra) { + if (cpi->oxcf.enable_smooth_interintra && + !cpi->sf.disable_smooth_interintra) { mbmi->use_wedge_interintra = 0; int j = 0; if (cpi->sf.reuse_inter_intra_mode == 0 || best_interintra_mode == INTERINTRA_MODES) { for (j = 0; j < INTERINTRA_MODES; ++j) { - if (!cpi->oxcf.enable_smooth_intra && + if ((!cpi->oxcf.enable_smooth_intra || cpi->sf.disable_smooth_intra) && (INTERINTRA_MODE)j == II_SMOOTH_PRED) continue; mbmi->interintra_mode = (INTERINTRA_MODE)j; @@ -8970,7 +9090,8 @@ static int handle_inter_intra_mode(const AV1_COMP *const cpi, } args->inter_intra_mode[mbmi->ref_frame[0]] = best_interintra_mode; } - assert(IMPLIES(!cpi->oxcf.enable_smooth_interintra, + assert(IMPLIES(!cpi->oxcf.enable_smooth_interintra || + cpi->sf.disable_smooth_interintra, best_interintra_mode != II_SMOOTH_PRED)); rmode = interintra_mode_cost[best_interintra_mode]; if (j == 0 || best_interintra_mode != II_SMOOTH_PRED) { @@ -8981,7 +9102,7 @@ static int handle_inter_intra_mode(const AV1_COMP *const cpi, } RD_STATS rd_stats; - rd = estimate_yrd_for_sb(cpi, bsize, x, INT64_MAX, &rd_stats); + rd = estimate_yrd_for_sb(cpi, bsize, x, ref_best_rd, &rd_stats); if (rd != INT64_MAX) { rd = RDCOST(x->rdmult, *rate_mv + rmode + rd_stats.rate + rwedge, rd_stats.dist); @@ -9002,7 +9123,8 @@ static int handle_inter_intra_mode(const AV1_COMP *const cpi, rwedge = av1_cost_literal(get_interintra_wedge_bits(bsize)) + x->wedge_interintra_cost[bsize][1]; - if (!cpi->oxcf.enable_smooth_interintra) { + if (!cpi->oxcf.enable_smooth_interintra || + cpi->sf.disable_smooth_interintra) { if (best_interintra_mode == INTERINTRA_MODES) { mbmi->interintra_mode = II_SMOOTH_PRED; best_interintra_mode = II_SMOOTH_PRED; @@ -9077,13 +9199,14 @@ static int handle_inter_intra_mode(const AV1_COMP *const cpi, } // Evaluate closer to true rd RD_STATS rd_stats; - rd = estimate_yrd_for_sb(cpi, bsize, x, INT64_MAX, &rd_stats); + rd = estimate_yrd_for_sb(cpi, bsize, x, ref_best_rd, &rd_stats); if (rd != INT64_MAX) { rd = RDCOST(x->rdmult, rmode + tmp_rate_mv + rwedge + rd_stats.rate, rd_stats.dist); } best_interintra_rd_wedge = rd; - if (!cpi->oxcf.enable_smooth_interintra && + if ((!cpi->oxcf.enable_smooth_interintra || + cpi->sf.disable_smooth_interintra) && best_interintra_rd_wedge == INT64_MAX) return -1; if (best_interintra_rd_wedge < best_interintra_rd_nowedge) { @@ -9098,10 +9221,14 @@ static int handle_inter_intra_mode(const AV1_COMP *const cpi, AOM_PLANE_Y, AOM_PLANE_Y); } } else { - if (!cpi->oxcf.enable_smooth_interintra) return -1; + if (!cpi->oxcf.enable_smooth_interintra || + cpi->sf.disable_smooth_interintra) + return -1; mbmi->use_wedge_interintra = 0; } - } // if (is_wedge_used) + } else { + if (best_interintra_rd == INT64_MAX) return -1; + } if (num_planes > 1) { av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, AOM_PLANE_U, num_planes - 1); @@ -9156,7 +9283,6 @@ static INLINE void obmc_check_identical_mv(MACROBLOCKD *xd, int rel_mi_col, nb_mi->interp_filters != current_mi->interp_filters) { ctxt->mv_field_check_result = 0; } - return; } // Check if the neighbors' motions used by obmc have same parameters as for @@ -9179,6 +9305,36 @@ int check_identical_obmc_mv_field(const AV1_COMMON *cm, MACROBLOCKD *xd, return mv_field_check_ctxt.mv_field_check_result; } +static int skip_interintra_based_on_first_pass_stats(const AV1_COMP *const cpi, + MACROBLOCK *const x, + BLOCK_SIZE bsize, + int mi_row, int mi_col) { + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + if (cpi->two_pass_partition_search && + cpi->sf.use_first_partition_pass_interintra_stats && + !x->cb_partition_scan) { + const int mi_width = mi_size_wide[bsize]; + const int mi_height = mi_size_high[bsize]; + // Search in the stats table to see if obmc motion mode was used in the + // first pass of partition search. + for (int row = mi_row; row < mi_row + mi_width; + row += FIRST_PARTITION_PASS_SAMPLE_REGION) { + for (int col = mi_col; col < mi_col + mi_height; + col += FIRST_PARTITION_PASS_SAMPLE_REGION) { + const int index = av1_first_partition_pass_stats_index(row, col); + const FIRST_PARTITION_PASS_STATS *const stats = + &x->first_partition_pass_stats[index]; + if (stats->interintra_motion_mode_count[mbmi->ref_frame[0]]) { + return 0; + } + } + } + return 1; + } + return 0; +} + // TODO(afergs): Refactor the MBMI references in here - there's four // TODO(afergs): Refactor optional args - add them to a struct or remove static int64_t motion_mode_rd( @@ -9199,6 +9355,7 @@ static int64_t motion_mode_rd( RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv; uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; const int rate_mv0 = *rate_mv; + int skip_interintra_mode = 0; const int interintra_allowed = cm->seq_params.enable_interintra_compound && is_interintra_allowed(mbmi) && mbmi->compound_idx; @@ -9270,26 +9427,27 @@ static int64_t motion_mode_rd( // SIMPLE_TRANSLATION mode: no need to recalculate. // The prediction is calculated before motion_mode_rd() is called in // handle_inter_mode() - if (cpi->sf.prune_single_motion_modes_by_simple_trans && - args->single_ref_first_pass == 0 && !is_comp_pred) { - if (simple_states->early_skipped) { - assert(simple_states->rd_stats.rdcost == INT64_MAX); - return INT64_MAX; + if (cpi->sf.prune_single_motion_modes_by_simple_trans && !is_comp_pred) { + if (args->single_ref_first_pass == 0) { + if (simple_states->early_skipped) { + assert(simple_states->rd_stats.rdcost == INT64_MAX); + return INT64_MAX; + } + if (simple_states->rd_stats.rdcost != INT64_MAX) { + best_rd = simple_states->rd_stats.rdcost; + best_rd_stats = simple_states->rd_stats; + best_rd_stats_y = simple_states->rd_stats_y; + best_rd_stats_uv = simple_states->rd_stats_uv; + memcpy(best_blk_skip, simple_states->blk_skip, + sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); + best_xskip = simple_states->skip; + best_disable_skip = simple_states->disable_skip; + best_mbmi = *mbmi; + } + continue; } - if (simple_states->rd_stats.rdcost != INT64_MAX) { - best_rd = simple_states->rd_stats.rdcost; - best_rd_stats = simple_states->rd_stats; - best_rd_stats_y = simple_states->rd_stats_y; - best_rd_stats_uv = simple_states->rd_stats_uv; - memcpy(best_blk_skip, simple_states->blk_skip, - sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); - best_xskip = simple_states->skip; - best_disable_skip = simple_states->disable_skip; - best_mbmi = *mbmi; - } - continue; + simple_states->early_skipped = 0; } - simple_states->early_skipped = 0; } else if (mbmi->motion_mode == OBMC_CAUSAL) { const uint32_t cur_mv = mbmi->mv[0].as_int; assert(!is_comp_pred); @@ -9378,6 +9536,9 @@ static int64_t motion_mode_rd( continue; } } else if (is_interintra_mode) { + skip_interintra_mode = skip_interintra_based_on_first_pass_stats( + cpi, x, bsize, mi_row, mi_col); + if (skip_interintra_mode) continue; const int ret = handle_inter_intra_mode( cpi, x, bsize, mi_row, mi_col, mbmi, args, ref_best_rd, &tmp_rate_mv, &tmp_rate2, orig_dst); @@ -9430,7 +9591,7 @@ static int64_t motion_mode_rd( } if (!do_tx_search) { - int64_t curr_sse; + int64_t curr_sse = -1; int est_residue_cost = 0; int64_t est_dist = 0; int64_t est_rd = 0; @@ -9440,7 +9601,8 @@ static int64_t motion_mode_rd( &est_residue_cost, &est_dist); (void)has_est_rd; assert(has_est_rd); - } else if (cpi->sf.inter_mode_rd_model_estimation == 2) { + } else if (cpi->sf.inter_mode_rd_model_estimation == 2 || + cpi->sf.use_nonrd_pick_mode) { model_rd_sb_fn[MODELRD_TYPE_MOTION_MODE_RD]( cpi, bsize, x, xd, 0, num_planes - 1, mi_row, mi_col, &est_residue_cost, &est_dist, NULL, &curr_sse, NULL, NULL, NULL); @@ -9457,18 +9619,25 @@ static int64_t motion_mode_rd( *best_est_rd = AOMMIN(*best_est_rd, rd_stats->rdcost); if (cm->current_frame.reference_mode == SINGLE_REFERENCE) { if (!is_comp_pred) { + assert(curr_sse >= 0); inter_modes_info_push(inter_modes_info, mode_rate, curr_sse, - rd_stats->rdcost, mbmi); + rd_stats->rdcost, false, NULL, rd_stats, + rd_stats_y, rd_stats_uv, mbmi); } } else { + assert(curr_sse >= 0); inter_modes_info_push(inter_modes_info, mode_rate, curr_sse, - rd_stats->rdcost, mbmi); + rd_stats->rdcost, false, NULL, rd_stats, + rd_stats_y, rd_stats_uv, mbmi); } } else { if (!txfm_search(cpi, tile_data, x, bsize, mi_row, mi_col, rd_stats, rd_stats_y, rd_stats_uv, rd_stats->rate, ref_best_rd)) { if (rd_stats_y->rate == INT_MAX && mode_index == 0) { - simple_states->early_skipped = 1; + if (cpi->sf.prune_single_motion_modes_by_simple_trans && + !is_comp_pred) { + simple_states->early_skipped = 1; + } return INT64_MAX; } continue; @@ -9484,6 +9653,15 @@ static int64_t motion_mode_rd( rd_stats_y->rate + rd_stats_uv->rate + x->skip_cost[skip_ctx][mbmi->skip]); } + + // 2 means to both do the tx search and also update the inter_modes_info + // structure, since some modes will be conditionally TX searched. + if (do_tx_search == 2) { + rd_stats->rdcost = curr_rd; + inter_modes_info_push(inter_modes_info, rd_stats->rate, rd_stats->sse, + curr_rd, true, x->blk_skip, rd_stats, rd_stats_y, + rd_stats_uv, mbmi); + } } if (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV) { @@ -9560,44 +9738,8 @@ static int64_t skip_mode_rd(RD_STATS *rd_stats, const AV1_COMP *const cpi, const int bh = block_size_high[plane_bsize]; av1_subtract_plane(x, bsize, plane); - int64_t sse; -#if CONFIG_ONE_PASS_SVM - if (plane == AOM_PLANE_Y && bsize >= BLOCK_8X8 && bw == bh) { - rd_stats->sse_0 = aom_sum_squares_2d_i16(p->src_diff, bw, bw / 2, bh / 2) - << 4; - rd_stats->sse_1 = - aom_sum_squares_2d_i16(p->src_diff + bw / 2, bw, bw / 2, bh / 2) << 4; - rd_stats->sse_2 = - aom_sum_squares_2d_i16(p->src_diff + bh / 2 * bw, bw, bw / 2, bh / 2) - << 4; - rd_stats->sse_3 = - aom_sum_squares_2d_i16(p->src_diff + bh / 2 * bw + bw / 2, bw, bw / 2, - bh / 2) - << 4; - - sse = - rd_stats->sse_0 + rd_stats->sse_1 + rd_stats->sse_2 + rd_stats->sse_3; - total_sse += sse; - - const int scaling_factor = MAX_MIB_SIZE * MAX_MIB_SIZE; - rd_stats->sse = sse; - rd_stats->sse_0 = rd_stats->sse_0 * scaling_factor; - rd_stats->sse_1 = rd_stats->sse_1 * scaling_factor; - rd_stats->sse_2 = rd_stats->sse_2 * scaling_factor; - rd_stats->sse_3 = rd_stats->sse_3 * scaling_factor; - rd_stats->y_sse = sse; - // TODO(chiyotsai@google.com): Don't manually set the flags - av1_reg_stat_skipmode_update(rd_stats, x->rdmult); - } else { - sse = aom_sum_squares_2d_i16(p->src_diff, bw, bw, bh); - sse = sse << 4; - total_sse += sse; - } -#else - sse = aom_sum_squares_2d_i16(p->src_diff, bw, bw, bh); - sse = sse << 4; + int64_t sse = aom_sum_squares_2d_i16(p->src_diff, bw, bw, bh) << 4; total_sse += sse; -#endif } const int skip_mode_ctx = av1_get_skip_mode_context(xd); rd_stats->dist = rd_stats->sse = total_sse; @@ -9717,14 +9859,12 @@ typedef struct { uint8_t *tmp_best_mask_buf; // backup of the best segmentation mask } CompoundTypeRdBuffers; -static int compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int mi_col, int mi_row, - int_mv *cur_mv, int masked_compound_used, - const BUFFER_SET *orig_dst, - const BUFFER_SET *tmp_dst, - CompoundTypeRdBuffers *buffers, int *rate_mv, - int64_t *rd, RD_STATS *rd_stats, - int64_t ref_best_rd, int *is_luma_interp_done) { +static int compound_type_rd( + const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int mi_col, + int mi_row, int_mv *cur_mv, int mode_search_mask, int masked_compound_used, + const BUFFER_SET *orig_dst, const BUFFER_SET *tmp_dst, + CompoundTypeRdBuffers *buffers, int *rate_mv, int64_t *rd, + RD_STATS *rd_stats, int64_t ref_best_rd, int *is_luma_interp_done) { const AV1_COMMON *cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = xd->mi[0]; @@ -9744,85 +9884,214 @@ static int compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x, COMPOUND_TYPE cur_type; int best_compmode_interinter_cost = 0; int calc_pred_masked_compound = 1; - int64_t comp_dist[COMPOUND_TYPES] = { INT64_MAX, INT64_MAX, INT64_MAX }; - int32_t comp_rate[COMPOUND_TYPES] = { INT_MAX, INT_MAX, INT_MAX }; - const int match_found = find_comp_rd_in_stats(x, mbmi, comp_rate, comp_dist); + int64_t comp_dist[COMPOUND_TYPES] = { INT64_MAX, INT64_MAX, INT64_MAX, + INT64_MAX }; + int32_t comp_rate[COMPOUND_TYPES] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; + int64_t comp_model_rd[COMPOUND_TYPES] = { INT64_MAX, INT64_MAX, INT64_MAX, + INT64_MAX }; + const int match_found = + find_comp_rd_in_stats(cpi, x, mbmi, comp_rate, comp_dist, comp_model_rd); + best_mv[0].as_int = cur_mv[0].as_int; best_mv[1].as_int = cur_mv[1].as_int; *rd = INT64_MAX; + int rate_sum, tmp_skip_txfm_sb; + int64_t dist_sum, tmp_skip_sse_sb; + int64_t comp_best_model_rd = INT64_MAX; + // Special handling if both compound_average and compound_distwtd + // are to be searched. In this case, first estimate between the two + // modes and then call estimate_yrd_for_sb() only for the better of + // the two. + const int try_average_comp = (mode_search_mask & (1 << COMPOUND_AVERAGE)); + const int try_distwtd_comp = + ((mode_search_mask & (1 << COMPOUND_DISTWTD)) && + cm->seq_params.order_hint_info.enable_dist_wtd_comp == 1 && + cpi->sf.use_dist_wtd_comp_flag != DIST_WTD_COMP_DISABLED); + const int try_average_and_distwtd_comp = + try_average_comp && try_distwtd_comp && + comp_rate[COMPOUND_AVERAGE] == INT_MAX && + comp_rate[COMPOUND_DISTWTD] == INT_MAX; for (cur_type = COMPOUND_AVERAGE; cur_type < COMPOUND_TYPES; cur_type++) { - if (cur_type != COMPOUND_AVERAGE && !masked_compound_used) break; + if (((1 << cur_type) & mode_search_mask) == 0) { + if (cur_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); + continue; + } if (!is_interinter_compound_used(cur_type, bsize)) continue; + if (cur_type >= COMPOUND_WEDGE && !masked_compound_used) break; + if (cur_type == COMPOUND_DISTWTD && !try_distwtd_comp) continue; + if (cur_type == COMPOUND_AVERAGE && try_average_and_distwtd_comp) continue; + + int64_t comp_model_rd_cur = INT64_MAX; tmp_rate_mv = *rate_mv; int64_t best_rd_cur = INT64_MAX; - mbmi->interinter_comp.type = cur_type; - int masked_type_cost = 0; - const int comp_group_idx_ctx = get_comp_group_idx_context(xd); const int comp_index_ctx = get_comp_index_context(cm, xd); - mbmi->compound_idx = 1; - if (cur_type == COMPOUND_AVERAGE) { + + if (cur_type == COMPOUND_DISTWTD && try_average_and_distwtd_comp) { + int est_rate[2]; + int64_t est_dist[2], est_rd[2]; + + int masked_type_cost[2] = { 0, 0 }; mbmi->comp_group_idx = 0; + + // First find the modeled rd cost for COMPOUND_AVERAGE + mbmi->interinter_comp.type = COMPOUND_AVERAGE; + mbmi->compound_idx = 1; if (masked_compound_used) { - masked_type_cost += x->comp_group_idx_cost[comp_group_idx_ctx][0]; + masked_type_cost[COMPOUND_AVERAGE] += + x->comp_group_idx_cost[comp_group_idx_ctx][mbmi->comp_group_idx]; } - masked_type_cost += x->comp_idx_cost[comp_index_ctx][1]; - rs2 = masked_type_cost; - const int64_t mode_rd = RDCOST(x->rdmult, rs2 + rd_stats->rate, 0); - if (mode_rd < ref_best_rd) { - // Reuse data if matching record is found - if (comp_rate[0] == INT_MAX) { - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - *is_luma_interp_done = 1; - RD_STATS est_rd_stats; - const int64_t est_rd = - estimate_yrd_for_sb(cpi, bsize, x, INT64_MAX, &est_rd_stats); - if (comp_rate[0] != INT_MAX) { - assert(comp_rate[0] == est_rd_stats.rate); - assert(comp_dist[0] == est_rd_stats.dist); - } - if (est_rd != INT64_MAX) { - best_rd_cur = RDCOST(x->rdmult, rs2 + *rate_mv + est_rd_stats.rate, - est_rd_stats.dist); - // Backup rate and distortion for future reuse - comp_rate[0] = est_rd_stats.rate; - comp_dist[0] = est_rd_stats.dist; - } - } else { - // Calculate RD cost based on stored stats - assert(comp_dist[0] != INT64_MAX); - best_rd_cur = - RDCOST(x->rdmult, rs2 + *rate_mv + comp_rate[0], comp_dist[0]); + masked_type_cost[COMPOUND_AVERAGE] += + x->comp_idx_cost[comp_index_ctx][mbmi->compound_idx]; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + *is_luma_interp_done = 1; + model_rd_sb_fn[MODELRD_CURVFIT]( + cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &est_rate[COMPOUND_AVERAGE], + &est_dist[COMPOUND_AVERAGE], NULL, NULL, NULL, NULL, NULL); + est_rate[COMPOUND_AVERAGE] += masked_type_cost[COMPOUND_AVERAGE]; + est_rd[COMPOUND_AVERAGE] = + RDCOST(x->rdmult, est_rate[COMPOUND_AVERAGE] + *rate_mv, + est_dist[COMPOUND_AVERAGE]); + restore_dst_buf(xd, *tmp_dst, 1); + + // Next find the modeled rd cost for COMPOUND_DISTWTD + mbmi->interinter_comp.type = COMPOUND_DISTWTD; + mbmi->compound_idx = 0; + if (masked_compound_used) { + masked_type_cost[COMPOUND_DISTWTD] += + x->comp_group_idx_cost[comp_group_idx_ctx][mbmi->comp_group_idx]; + } + masked_type_cost[COMPOUND_DISTWTD] += + x->comp_idx_cost[comp_index_ctx][mbmi->compound_idx]; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + model_rd_sb_fn[MODELRD_CURVFIT]( + cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &est_rate[COMPOUND_DISTWTD], + &est_dist[COMPOUND_DISTWTD], NULL, NULL, NULL, NULL, NULL); + est_rate[COMPOUND_DISTWTD] += masked_type_cost[COMPOUND_DISTWTD]; + est_rd[COMPOUND_DISTWTD] = + RDCOST(x->rdmult, est_rate[COMPOUND_DISTWTD] + *rate_mv, + est_dist[COMPOUND_DISTWTD]); + + // Choose the better of the two based on modeled cost and call + // estimate_yrd_for_sb() for that one. + if (est_rd[COMPOUND_AVERAGE] <= est_rd[COMPOUND_DISTWTD]) { + mbmi->interinter_comp.type = COMPOUND_AVERAGE; + mbmi->compound_idx = 1; + restore_dst_buf(xd, *orig_dst, 1); + RD_STATS est_rd_stats; + const int64_t est_rd_ = + estimate_yrd_for_sb(cpi, bsize, x, ref_best_rd, &est_rd_stats); + rs2 = masked_type_cost[COMPOUND_AVERAGE]; + if (est_rd_ != INT64_MAX) { + best_rd_cur = RDCOST(x->rdmult, rs2 + *rate_mv + est_rd_stats.rate, + est_rd_stats.dist); + restore_dst_buf(xd, *tmp_dst, 1); + comp_rate[COMPOUND_AVERAGE] = est_rd_stats.rate; + comp_dist[COMPOUND_AVERAGE] = est_rd_stats.dist; + comp_model_rd[COMPOUND_AVERAGE] = est_rd[COMPOUND_AVERAGE]; + comp_model_rd_cur = est_rd[COMPOUND_AVERAGE]; + } + restore_dst_buf(xd, *tmp_dst, 1); + } else { + RD_STATS est_rd_stats; + const int64_t est_rd_ = + estimate_yrd_for_sb(cpi, bsize, x, ref_best_rd, &est_rd_stats); + rs2 = masked_type_cost[COMPOUND_DISTWTD]; + if (est_rd_ != INT64_MAX) { + best_rd_cur = RDCOST(x->rdmult, rs2 + *rate_mv + est_rd_stats.rate, + est_rd_stats.dist); + comp_rate[COMPOUND_DISTWTD] = est_rd_stats.rate; + comp_dist[COMPOUND_DISTWTD] = est_rd_stats.dist; + comp_model_rd[COMPOUND_DISTWTD] = est_rd[COMPOUND_DISTWTD]; + comp_model_rd_cur = est_rd[COMPOUND_DISTWTD]; } } - // use spare buffer for following compound type try - restore_dst_buf(xd, *tmp_dst, 1); } else { - mbmi->comp_group_idx = 1; - masked_type_cost += x->comp_group_idx_cost[comp_group_idx_ctx][1]; - masked_type_cost += x->compound_type_cost[bsize][cur_type - 1]; - rs2 = masked_type_cost; + mbmi->interinter_comp.type = cur_type; + int masked_type_cost = 0; + if (cur_type == COMPOUND_AVERAGE || cur_type == COMPOUND_DISTWTD) { + mbmi->comp_group_idx = 0; + mbmi->compound_idx = (cur_type == COMPOUND_AVERAGE); + if (masked_compound_used) { + masked_type_cost += + x->comp_group_idx_cost[comp_group_idx_ctx][mbmi->comp_group_idx]; + } + masked_type_cost += + x->comp_idx_cost[comp_index_ctx][mbmi->compound_idx]; + rs2 = masked_type_cost; + const int64_t mode_rd = RDCOST(x->rdmult, rs2 + rd_stats->rate, 0); + if (mode_rd < ref_best_rd) { + // Reuse data if matching record is found + if (comp_rate[cur_type] == INT_MAX) { + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, + bsize, AOM_PLANE_Y, AOM_PLANE_Y); + if (cur_type == COMPOUND_AVERAGE) *is_luma_interp_done = 1; + RD_STATS est_rd_stats; + const int64_t est_rd = + estimate_yrd_for_sb(cpi, bsize, x, ref_best_rd, &est_rd_stats); + if (comp_rate[cur_type] != INT_MAX) { + assert(comp_rate[cur_type] == est_rd_stats.rate); + assert(comp_dist[cur_type] == est_rd_stats.dist); + } + if (est_rd != INT64_MAX) { + best_rd_cur = + RDCOST(x->rdmult, rs2 + *rate_mv + est_rd_stats.rate, + est_rd_stats.dist); + model_rd_sb_fn[MODELRD_TYPE_MASKED_COMPOUND]( + cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &rate_sum, &dist_sum, + &tmp_skip_txfm_sb, &tmp_skip_sse_sb, NULL, NULL, NULL); + comp_model_rd_cur = + RDCOST(x->rdmult, rs2 + *rate_mv + rate_sum, dist_sum); - if (((*rd / cpi->max_comp_type_rd_threshold_div) * - cpi->max_comp_type_rd_threshold_mul) < ref_best_rd) { - const COMPOUND_TYPE compound_type = mbmi->interinter_comp.type; + // Backup rate and distortion for future reuse + comp_rate[cur_type] = est_rd_stats.rate; + comp_dist[cur_type] = est_rd_stats.dist; + comp_model_rd[cur_type] = comp_model_rd_cur; + } + } else { + // Calculate RD cost based on stored stats + assert(comp_dist[cur_type] != INT64_MAX); + best_rd_cur = + RDCOST(x->rdmult, rs2 + *rate_mv + comp_rate[cur_type], + comp_dist[cur_type]); + comp_model_rd_cur = comp_model_rd[cur_type]; + } + } + // use spare buffer for following compound type try + if (cur_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); + } else { + mbmi->comp_group_idx = 1; + mbmi->compound_idx = 1; + masked_type_cost += + x->comp_group_idx_cost[comp_group_idx_ctx][mbmi->comp_group_idx]; + masked_type_cost += + x->compound_type_cost[bsize][cur_type - COMPOUND_WEDGE]; + rs2 = masked_type_cost; - if (!((compound_type == COMPOUND_WEDGE && - !enable_wedge_interinter_search(x, cpi)) || - (compound_type == COMPOUND_DIFFWTD && - !cpi->oxcf.enable_diff_wtd_comp))) - best_rd_cur = build_and_cost_compound_type( - cpi, x, cur_mv, bsize, this_mode, &rs2, *rate_mv, orig_dst, - &tmp_rate_mv, preds0, preds1, buffers->residual1, buffers->diff10, - strides, mi_row, mi_col, rd_stats->rate, ref_best_rd, - &calc_pred_masked_compound, comp_rate, comp_dist); + if (((*rd / cpi->max_comp_type_rd_threshold_div) * + cpi->max_comp_type_rd_threshold_mul) < ref_best_rd) { + const COMPOUND_TYPE compound_type = mbmi->interinter_comp.type; + + if (!((compound_type == COMPOUND_WEDGE && + !enable_wedge_interinter_search(x, cpi)) || + (compound_type == COMPOUND_DIFFWTD && + !cpi->oxcf.enable_diff_wtd_comp))) + best_rd_cur = build_and_cost_compound_type( + cpi, x, cur_mv, bsize, this_mode, &rs2, *rate_mv, orig_dst, + &tmp_rate_mv, preds0, preds1, buffers->residual1, + buffers->diff10, strides, mi_row, mi_col, rd_stats->rate, + ref_best_rd, &calc_pred_masked_compound, comp_rate, comp_dist, + comp_model_rd, comp_best_model_rd, &comp_model_rd_cur); + } } } if (best_rd_cur < *rd) { *rd = best_rd_cur; + comp_best_model_rd = comp_model_rd_cur; best_compound_data = mbmi->interinter_comp; - if (masked_compound_used && cur_type != COMPOUND_TYPES - 1) { + if (masked_compound_used && cur_type >= COMPOUND_WEDGE) { memcpy(buffers->tmp_best_mask_buf, xd->seg_mask, mask_len); } best_compmode_interinter_cost = rs2; @@ -9842,8 +10111,8 @@ static int compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x, mbmi->mv[1].as_int = cur_mv[1].as_int; } if (mbmi->interinter_comp.type != best_compound_data.type) { - mbmi->comp_group_idx = - (best_compound_data.type == COMPOUND_AVERAGE) ? 0 : 1; + mbmi->comp_group_idx = (best_compound_data.type < COMPOUND_WEDGE) ? 0 : 1; + mbmi->compound_idx = !(best_compound_data.type == COMPOUND_DISTWTD); mbmi->interinter_comp = best_compound_data; memcpy(xd->seg_mask, buffers->tmp_best_mask_buf, mask_len); } @@ -9857,7 +10126,8 @@ static int compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x, } restore_dst_buf(xd, *orig_dst, 1); if (!match_found) - save_comp_rd_search_stat(x, mbmi, comp_rate, comp_dist, cur_mv); + save_comp_rd_search_stat(x, mbmi, comp_rate, comp_dist, comp_model_rd, + cur_mv); return best_compmode_interinter_cost; } @@ -9899,7 +10169,7 @@ typedef struct { } inter_mode_info; static int64_t handle_inter_mode( - const AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *x, + AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *x, BLOCK_SIZE bsize, RD_STATS *rd_stats, RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv, int *disable_skip, int mi_row, int mi_col, HandleInterModeArgs *args, int64_t ref_best_rd, uint8_t *const tmp_buf, @@ -9950,11 +10220,20 @@ static int64_t handle_inter_mode( int backup_rate_mv = 0; inter_mode_info mode_info[MAX_REF_MV_SERCH]; - int comp_idx; - const int search_dist_wtd_comp = - is_comp_pred & cm->seq_params.order_hint_info.enable_dist_wtd_comp & - (mbmi->mode != GLOBAL_GLOBALMV) & - (cpi->sf.use_dist_wtd_comp_flag != DIST_WTD_COMP_DISABLED); + int mode_search_mask[2]; + const int do_two_loop_comp_search = + is_comp_pred && cpi->sf.two_loop_comp_search; + if (do_two_loop_comp_search) { + // TODO(debargha): Change this to try alternate ways of splitting + // modes while doing two pass compound_mode search. + mode_search_mask[0] = (1 << COMPOUND_AVERAGE); + } else { + mode_search_mask[0] = (1 << COMPOUND_AVERAGE) | (1 << COMPOUND_DISTWTD) | + (1 << COMPOUND_WEDGE) | (1 << COMPOUND_DIFFWTD); + } + mode_search_mask[1] = ((1 << COMPOUND_AVERAGE) | (1 << COMPOUND_DISTWTD) | + (1 << COMPOUND_WEDGE) | (1 << COMPOUND_DIFFWTD)) - + mode_search_mask[0]; // TODO(jingning): This should be deprecated shortly. const int has_nearmv = have_nearmv_in_inter_mode(mbmi->mode) ? 1 : 0; @@ -10011,43 +10290,35 @@ static int64_t handle_inter_mode( } const RD_STATS backup_rd_stats = *rd_stats; - // If !search_dist_wtd_comp, we need to force mbmi->compound_idx = 1. - for (comp_idx = 1; comp_idx >= !search_dist_wtd_comp; --comp_idx) { + + for (int comp_loop_idx = 0; comp_loop_idx <= do_two_loop_comp_search; + ++comp_loop_idx) { int rs = 0; int compmode_interinter_cost = 0; - mbmi->compound_idx = comp_idx; - if (is_comp_pred && comp_idx == 0) { - *rd_stats = backup_rd_stats; - mbmi->interinter_comp.type = COMPOUND_AVERAGE; - mbmi->num_proj_ref = 0; - mbmi->motion_mode = SIMPLE_TRANSLATION; - mbmi->comp_group_idx = 0; - const int comp_index_ctx = get_comp_index_context(cm, xd); - compmode_interinter_cost += x->comp_idx_cost[comp_index_ctx][0]; - } + if (is_comp_pred && comp_loop_idx == 1) *rd_stats = backup_rd_stats; int_mv cur_mv[2]; if (!build_cur_mv(cur_mv, this_mode, cm, x)) { continue; } if (have_newmv_in_inter_mode(this_mode)) { - if (comp_idx == 0) { + if (comp_loop_idx == 1) { cur_mv[0] = backup_mv[0]; cur_mv[1] = backup_mv[1]; rate_mv = backup_rate_mv; } +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, handle_newmv_time); +#endif if (cpi->sf.prune_single_motion_modes_by_simple_trans && args->single_ref_first_pass == 0 && !is_comp_pred) { const int ref0 = mbmi->ref_frame[0]; newmv_ret_val = args->single_newmv_valid[ref_mv_idx][ref0] ? 0 : 1; cur_mv[0] = args->single_newmv[ref_mv_idx][ref0]; rate_mv = args->single_newmv_rate[ref_mv_idx][ref0]; - } else if (!(search_dist_wtd_comp && - (cpi->sf.use_dist_wtd_comp_flag == - DIST_WTD_COMP_SKIP_MV_SEARCH) && - comp_idx == 0)) { + } else if (comp_loop_idx == 0) { newmv_ret_val = handle_newmv(cpi, x, bsize, cur_mv, mi_row, mi_col, &rate_mv, args); @@ -10057,6 +10328,9 @@ static int64_t handle_inter_mode( backup_mv[1] = cur_mv[1]; backup_rate_mv = rate_mv; } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, handle_newmv_time); +#endif if (newmv_ret_val != 0) { continue; @@ -10151,49 +10425,90 @@ static int64_t handle_inter_mode( continue; } +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, compound_type_rd_time); +#endif int skip_build_pred = 0; - if (is_comp_pred && comp_idx) { - // Find matching interp filter or set to default interp filter - const int need_search = - av1_is_interp_needed(xd) && av1_is_interp_search_needed(xd); - int match_found = -1; - const InterpFilter assign_filter = cm->interp_filter; - int is_luma_interp_done = 0; - if (cpi->sf.skip_repeat_interpolation_filter_search && need_search) { - match_found = find_interp_filter_in_stats(x, mbmi); - } - if (!need_search || match_found == -1) { - set_default_interp_filters(mbmi, assign_filter); - } - - int64_t best_rd_compound; - compmode_interinter_cost = compound_type_rd( - cpi, x, bsize, mi_col, mi_row, cur_mv, masked_compound_used, - &orig_dst, &tmp_dst, rd_buffers, &rate_mv, &best_rd_compound, - rd_stats, ref_best_rd, &is_luma_interp_done); - if (ref_best_rd < INT64_MAX && - (best_rd_compound >> 4) * 13 > ref_best_rd) { - restore_dst_buf(xd, orig_dst, num_planes); - continue; - } - // No need to call av1_enc_build_inter_predictor for luma if - // COMPOUND_AVERAGE is selected because it is the first - // candidate in compound_type_rd, and the following - // compound types searching uses tmp_dst buffer - if (mbmi->interinter_comp.type == COMPOUND_AVERAGE && - is_luma_interp_done) { - if (num_planes > 1) { - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, - bsize, AOM_PLANE_U, num_planes - 1); + if (is_comp_pred) { + if (mode_search_mask[comp_loop_idx] == (1 << COMPOUND_AVERAGE)) { + // Only compound_average + mbmi->interinter_comp.type = COMPOUND_AVERAGE; + mbmi->num_proj_ref = 0; + mbmi->motion_mode = SIMPLE_TRANSLATION; + mbmi->comp_group_idx = 0; + mbmi->compound_idx = 1; + const int comp_index_ctx = get_comp_index_context(cm, xd); + compmode_interinter_cost += + x->comp_idx_cost[comp_index_ctx][mbmi->compound_idx]; + } else if (mode_search_mask[comp_loop_idx] == (1 << COMPOUND_DISTWTD)) { + // Only compound_distwtd + if (!cm->seq_params.order_hint_info.enable_dist_wtd_comp || + cpi->sf.use_dist_wtd_comp_flag == DIST_WTD_COMP_DISABLED || + (do_two_loop_comp_search && mbmi->mode == GLOBAL_GLOBALMV)) + continue; + mbmi->interinter_comp.type = COMPOUND_DISTWTD; + mbmi->num_proj_ref = 0; + mbmi->motion_mode = SIMPLE_TRANSLATION; + mbmi->comp_group_idx = 0; + mbmi->compound_idx = 0; + const int comp_index_ctx = get_comp_index_context(cm, xd); + compmode_interinter_cost += + x->comp_idx_cost[comp_index_ctx][mbmi->compound_idx]; + } else { + // Find matching interp filter or set to default interp filter + const int need_search = + av1_is_interp_needed(xd) && av1_is_interp_search_needed(xd); + int match_found = -1; + const InterpFilter assign_filter = cm->interp_filter; + int is_luma_interp_done = 0; + if (cpi->sf.skip_repeat_interpolation_filter_search && need_search) { + match_found = find_interp_filter_in_stats(x, mbmi); + } + if (!need_search || match_found == -1) { + set_default_interp_filters(mbmi, assign_filter); + } + + int64_t best_rd_compound; + compmode_interinter_cost = compound_type_rd( + cpi, x, bsize, mi_col, mi_row, cur_mv, + mode_search_mask[comp_loop_idx], masked_compound_used, &orig_dst, + &tmp_dst, rd_buffers, &rate_mv, &best_rd_compound, rd_stats, + ref_best_rd, &is_luma_interp_done); + if (ref_best_rd < INT64_MAX && + (best_rd_compound >> 4) * (11 + 2 * do_two_loop_comp_search) > + ref_best_rd) { + restore_dst_buf(xd, orig_dst, num_planes); + continue; + } + // No need to call av1_enc_build_inter_predictor for luma if + // COMPOUND_AVERAGE is selected because it is the first + // candidate in compound_type_rd, and the following + // compound types searching uses tmp_dst buffer + + if (mbmi->interinter_comp.type == COMPOUND_AVERAGE && + is_luma_interp_done) { + if (num_planes > 1) { + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, + bsize, AOM_PLANE_U, num_planes - 1); + } + skip_build_pred = 1; } - skip_build_pred = 1; } } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, compound_type_rd_time); +#endif +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, interpolation_filter_search_time); +#endif ret_val = interpolation_filter_search( x, cpi, tile_data, bsize, mi_row, mi_col, &tmp_dst, &orig_dst, args->single_filter, &rd, &rs, &skip_txfm_sb, &skip_sse_sb, - skip_build_pred, args, ref_best_rd); + &skip_build_pred, args, ref_best_rd); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, interpolation_filter_search_time); +#endif if (args->modelled_rd != NULL && !is_comp_pred) { args->modelled_rd[this_mode][ref_mv_idx][refs[0]] = rd; } @@ -10224,9 +10539,12 @@ static int64_t handle_inter_mode( } } rd_stats->rate += compmode_interinter_cost; + if (skip_build_pred != 1) { + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize, + 0, av1_num_planes(cm) - 1); + } - if (search_dist_wtd_comp && cpi->sf.dist_wtd_comp_fast_tx_search && - comp_idx == 0) { + if (cpi->sf.second_loop_comp_fast_tx_search && comp_loop_idx == 1) { // TODO(chengchen): this speed feature introduces big loss. // Need better estimation of rate distortion. int dummy_rate; @@ -10251,10 +10569,16 @@ static int64_t handle_inter_mode( rd_stats_y->dist = plane_dist[0]; rd_stats_uv->dist = plane_dist[1] + plane_dist[2]; } else { +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, motion_mode_rd_time); +#endif ret_val = motion_mode_rd(cpi, tile_data, x, bsize, rd_stats, rd_stats_y, rd_stats_uv, disable_skip, mi_row, mi_col, args, ref_best_rd, refs, &rate_mv, &orig_dst, best_est_rd, do_tx_search, inter_modes_info); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, motion_mode_rd_time); +#endif } mode_info[ref_mv_idx].mv.as_int = mbmi->mv[0].as_int; mode_info[ref_mv_idx].rate_mv = rate_mv; @@ -10403,7 +10727,8 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, const int bestsme = av1_full_pixel_search( cpi, x, bsize, &mvp_full, step_param, cpi->sf.mv.search_method, 0, sadpb, cond_cost_list(cpi, cost_list), &dv_ref.as_mv, INT_MAX, 1, - (MI_SIZE * mi_col), (MI_SIZE * mi_row), 1); + (MI_SIZE * mi_col), (MI_SIZE * mi_row), 1, + &cpi->ss_cfg[SS_CFG_LOOKAHEAD]); x->mv_limits = tmp_mv_limits; if (bestsme == INT_MAX) continue; @@ -10585,15 +10910,6 @@ static void calc_target_weighted_pred(const AV1_COMMON *cm, const MACROBLOCK *x, int above_stride, const uint8_t *left, int left_stride); -static const int ref_frame_flag_list[REF_FRAMES] = { 0, - AOM_LAST_FLAG, - AOM_LAST2_FLAG, - AOM_LAST3_FLAG, - AOM_GOLD_FLAG, - AOM_BWD_FLAG, - AOM_ALT2_FLAG, - AOM_ALT_FLAG }; - static void rd_pick_skip_mode(RD_STATS *rd_cost, InterModeSearchState *search_state, const AV1_COMP *const cpi, MACROBLOCK *const x, @@ -10626,6 +10942,10 @@ static void rd_pick_skip_mode(RD_STATS *rd_cost, return; } + if (!cpi->oxcf.enable_onesided_comp && cpi->all_one_sided_refs) { + return; + } + mbmi->mode = this_mode; mbmi->uv_mode = UV_DC_PRED; mbmi->ref_frame[0] = ref_frame; @@ -10729,13 +11049,6 @@ static void rd_pick_skip_mode(RD_STATS *rd_cost, rd_cost->dist = rd_cost->sse = skip_mode_rd_stats.dist; rd_cost->rdcost = skip_mode_rd_stats.rdcost; -#if CONFIG_ONE_PASS_SVM - if (bsize >= BLOCK_8X8 && - block_size_high[bsize] == block_size_wide[bsize]) { - av1_copy_reg_stat(rd_cost, &skip_mode_rd_stats); - } -#endif - search_state->best_rd = rd_cost->rdcost; search_state->best_skip2 = 1; search_state->best_mode_skippable = 1; @@ -10843,14 +11156,94 @@ static void sf_refine_fast_tx_type_search( } } -// Contains information on which modes to skip. The last entry contains -// information on whether the reference frames should should be skipped. -typedef struct mode_skip_mask_struct { - uint32_t mode[REF_FRAMES]; - uint16_t ref_frame1; - uint16_t ref_frame2; +typedef struct { + // Mask for each reference frame, specifying which prediction modes to NOT try + // during search. + uint32_t pred_modes[REF_FRAMES]; + // If ref_combo[i][j + 1] is true, do NOT try prediction using combination of + // reference frames (i, j). + // Note: indexing with 'j + 1' is due to the fact that 2nd reference can be -1 + // (NONE_FRAME). + bool ref_combo[REF_FRAMES][REF_FRAMES + 1]; } mode_skip_mask_t; +// Update 'ref_combo' mask to disable given 'ref' in single and compound modes. +static void disable_reference(MV_REFERENCE_FRAME ref, + bool ref_combo[REF_FRAMES][REF_FRAMES + 1]) { + for (MV_REFERENCE_FRAME ref2 = NONE_FRAME; ref2 < REF_FRAMES; ++ref2) { + ref_combo[ref][ref2 + 1] = true; + } +} + +// Update 'ref_combo' mask to disable all inter references except ALTREF. +static void disable_inter_references_except_altref( + bool ref_combo[REF_FRAMES][REF_FRAMES + 1]) { + disable_reference(LAST_FRAME, ref_combo); + disable_reference(LAST2_FRAME, ref_combo); + disable_reference(LAST3_FRAME, ref_combo); + disable_reference(GOLDEN_FRAME, ref_combo); + disable_reference(BWDREF_FRAME, ref_combo); + disable_reference(ALTREF2_FRAME, ref_combo); +} + +static const MV_REFERENCE_FRAME reduced_ref_combos[][2] = { + { LAST_FRAME, NONE_FRAME }, { ALTREF_FRAME, NONE_FRAME }, + { LAST_FRAME, ALTREF_FRAME }, { GOLDEN_FRAME, NONE_FRAME }, + { INTRA_FRAME, NONE_FRAME }, { GOLDEN_FRAME, ALTREF_FRAME }, + { LAST_FRAME, GOLDEN_FRAME }, { LAST_FRAME, INTRA_FRAME }, + { LAST_FRAME, BWDREF_FRAME }, { LAST_FRAME, LAST3_FRAME }, + { GOLDEN_FRAME, BWDREF_FRAME }, { GOLDEN_FRAME, INTRA_FRAME }, + { BWDREF_FRAME, NONE_FRAME }, { BWDREF_FRAME, ALTREF_FRAME }, + { ALTREF_FRAME, INTRA_FRAME }, { BWDREF_FRAME, INTRA_FRAME }, +}; + +static const MV_REFERENCE_FRAME real_time_ref_combos[][2] = { + { LAST_FRAME, NONE_FRAME }, + { ALTREF_FRAME, NONE_FRAME }, + { GOLDEN_FRAME, NONE_FRAME }, + { INTRA_FRAME, NONE_FRAME } +}; + +typedef enum { REF_SET_FULL, REF_SET_REDUCED, REF_SET_REALTIME } REF_SET; + +static void default_skip_mask(mode_skip_mask_t *mask, REF_SET ref_set) { + if (ref_set == REF_SET_FULL) { + // Everything available by default. + memset(mask, 0, sizeof(*mask)); + } else { + // All modes available by default. + memset(mask->pred_modes, 0, sizeof(mask->pred_modes)); + // All references disabled first. + for (MV_REFERENCE_FRAME ref1 = INTRA_FRAME; ref1 < REF_FRAMES; ++ref1) { + for (MV_REFERENCE_FRAME ref2 = NONE_FRAME; ref2 < REF_FRAMES; ++ref2) { + mask->ref_combo[ref1][ref2 + 1] = true; + } + } + const MV_REFERENCE_FRAME(*ref_set_combos)[2]; + int num_ref_combos; + + // Then enable reduced set of references explicitly. + switch (ref_set) { + case REF_SET_REDUCED: + ref_set_combos = reduced_ref_combos; + num_ref_combos = + (int)sizeof(reduced_ref_combos) / sizeof(reduced_ref_combos[0]); + break; + case REF_SET_REALTIME: + ref_set_combos = real_time_ref_combos; + num_ref_combos = + (int)sizeof(real_time_ref_combos) / sizeof(real_time_ref_combos[0]); + break; + default: assert(0); num_ref_combos = 0; + } + + for (int i = 0; i < num_ref_combos; ++i) { + const MV_REFERENCE_FRAME *const this_combo = ref_set_combos[i]; + mask->ref_combo[this_combo[0]][this_combo[1] + 1] = false; + } + } +} + static void init_mode_skip_mask(mode_skip_mask_t *mask, const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize) { const AV1_COMMON *const cm = &cpi->common; @@ -10859,8 +11252,14 @@ static void init_mode_skip_mask(mode_skip_mask_t *mask, const AV1_COMP *cpi, MB_MODE_INFO *const mbmi = xd->mi[0]; unsigned char segment_id = mbmi->segment_id; const SPEED_FEATURES *const sf = &cpi->sf; + REF_SET ref_set = REF_SET_FULL; - memset(mask, 0, sizeof(*mask)); + if (sf->use_real_time_ref_set) + ref_set = REF_SET_REALTIME; + else if (cpi->oxcf.enable_reduced_reference_set) + ref_set = REF_SET_REDUCED; + + default_skip_mask(mask, ref_set); int min_pred_mv_sad = INT_MAX; MV_REFERENCE_FRAME ref_frame; @@ -10868,42 +11267,34 @@ static void init_mode_skip_mask(mode_skip_mask_t *mask, const AV1_COMP *cpi, min_pred_mv_sad = AOMMIN(min_pred_mv_sad, x->pred_mv_sad[ref_frame]); for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { - if (!(cpi->ref_frame_flags & ref_frame_flag_list[ref_frame])) { - // Skip checking missing references in both single and compound reference - // modes. Note that a mode will be skipped iff both reference frames - // are masked out. - mask->ref_frame1 |= (1 << ref_frame); - mask->ref_frame2 |= SECOND_REF_FRAME_MASK; + if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame])) { + // Skip checking missing reference in both single and compound reference + // modes. + disable_reference(ref_frame, mask->ref_combo); } else { // Skip fixed mv modes for poor references if ((x->pred_mv_sad[ref_frame] >> 2) > min_pred_mv_sad) { - mask->mode[ref_frame] |= INTER_NEAREST_NEAR_ZERO; + mask->pred_modes[ref_frame] |= INTER_NEAREST_NEAR_ZERO; } } - // If the segment reference frame feature is enabled.... - // then do nothing if the current ref frame is not allowed.. if (segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) && get_segdata(seg, segment_id, SEG_LVL_REF_FRAME) != (int)ref_frame) { - mask->ref_frame1 |= (1 << ref_frame); - mask->ref_frame2 |= SECOND_REF_FRAME_MASK; + // Reference not used for the segment. + disable_reference(ref_frame, mask->ref_combo); } } - // Disable this drop out case if the ref frame - // segment level feature is enabled for this segment. This is to - // prevent the possibility that we end up unable to pick any mode. + // Note: We use the following drop-out only if the SEG_LVL_REF_FRAME feature + // is disabled for this segment. This is to prevent the possibility that we + // end up unable to pick any mode. if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) { // Only consider GLOBALMV/ALTREF_FRAME for alt ref frame, // unless ARNR filtering is enabled in which case we want // an unfiltered alternative. We allow near/nearest as well // because they may result in zero-zero MVs but be cheaper. if (cpi->rc.is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) { - mask->ref_frame1 = (1 << LAST_FRAME) | (1 << LAST2_FRAME) | - (1 << LAST3_FRAME) | (1 << BWDREF_FRAME) | - (1 << ALTREF2_FRAME) | (1 << GOLDEN_FRAME); - mask->ref_frame2 = SECOND_REF_FRAME_MASK; - // TODO(zoeliu): To further explore whether following needs to be done for - // BWDREF_FRAME as well. - mask->mode[ALTREF_FRAME] = ~INTER_NEAREST_NEAR_ZERO; + disable_inter_references_except_altref(mask->ref_combo); + + mask->pred_modes[ALTREF_FRAME] = ~INTER_NEAREST_NEAR_ZERO; const MV_REFERENCE_FRAME tmp_ref_frames[2] = { ALTREF_FRAME, NONE_FRAME }; int_mv near_mv, nearest_mv, global_mv; get_this_mv(&nearest_mv, NEARESTMV, 0, 0, tmp_ref_frames, x->mbmi_ext); @@ -10911,61 +11302,39 @@ static void init_mode_skip_mask(mode_skip_mask_t *mask, const AV1_COMP *cpi, get_this_mv(&global_mv, GLOBALMV, 0, 0, tmp_ref_frames, x->mbmi_ext); if (near_mv.as_int != global_mv.as_int) - mask->mode[ALTREF_FRAME] |= (1 << NEARMV); + mask->pred_modes[ALTREF_FRAME] |= (1 << NEARMV); if (nearest_mv.as_int != global_mv.as_int) - mask->mode[ALTREF_FRAME] |= (1 << NEARESTMV); + mask->pred_modes[ALTREF_FRAME] |= (1 << NEARESTMV); } } if (cpi->rc.is_src_frame_alt_ref) { if (sf->alt_ref_search_fp) { - assert(cpi->ref_frame_flags & ref_frame_flag_list[ALTREF_FRAME]); - mask->mode[ALTREF_FRAME] = 0; - mask->ref_frame1 = ~(1 << ALTREF_FRAME); - mask->ref_frame2 = SECOND_REF_FRAME_MASK; + assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]); + mask->pred_modes[ALTREF_FRAME] = 0; + disable_inter_references_except_altref(mask->ref_combo); + disable_reference(INTRA_FRAME, mask->ref_combo); } } if (sf->alt_ref_search_fp) if (!cm->show_frame && x->pred_mv_sad[GOLDEN_FRAME] < INT_MAX) if (x->pred_mv_sad[ALTREF_FRAME] > (x->pred_mv_sad[GOLDEN_FRAME] << 1)) - mask->mode[ALTREF_FRAME] |= INTER_ALL; + mask->pred_modes[ALTREF_FRAME] |= INTER_ALL; if (sf->adaptive_mode_search) { if (cm->show_frame && !cpi->rc.is_src_frame_alt_ref && cpi->rc.frames_since_golden >= 3) if ((x->pred_mv_sad[GOLDEN_FRAME] >> 1) > x->pred_mv_sad[LAST_FRAME]) - mask->mode[GOLDEN_FRAME] |= INTER_ALL; + mask->pred_modes[GOLDEN_FRAME] |= INTER_ALL; } if (bsize > sf->max_intra_bsize) { - mask->ref_frame1 |= (1 << INTRA_FRAME); - mask->ref_frame2 |= (1 << INTRA_FRAME); + disable_reference(INTRA_FRAME, mask->ref_combo); } - mask->mode[INTRA_FRAME] |= ~(sf->intra_y_mode_mask[max_txsize_lookup[bsize]]); - - // Disable some frames to enforce max number of reference frames requested. - // TODO(urvang): Should this logic be moved to enforce_max_ref_frames()? - const MV_REFERENCE_FRAME disable_order[] = { - LAST3_FRAME, LAST2_FRAME, ALTREF2_FRAME, BWDREF_FRAME, - // GOLDEN_FRAME, - }; - assert(cpi->oxcf.max_reference_frames <= INTER_REFS_PER_FRAME); - const int num_frames_to_disable = - INTER_REFS_PER_FRAME - cpi->oxcf.max_reference_frames; - for (int i = 0; i < num_frames_to_disable; ++i) { - const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i]; - - mask->ref_frame1 |= (1 << ref_frame_to_disable); - mask->ref_frame2 |= (1 << ref_frame_to_disable); - - if (ref_frame_to_disable == BWDREF_FRAME && - (cpi->ref_frame_flags & AOM_BWD_FLAG)) { - mask->ref_frame1 |= (1 << ALTREF_FRAME); - mask->ref_frame2 |= (1 << ALTREF_FRAME); - } - } + mask->pred_modes[INTRA_FRAME] |= + ~(sf->intra_y_mode_mask[max_txsize_lookup[bsize]]); } // Please add/modify parameter setting in this function, making it consistent @@ -11022,9 +11391,8 @@ static void set_params_rd_pick_inter_mode( for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { x->pred_mv_sad[ref_frame] = INT_MAX; x->mbmi_ext->mode_context[ref_frame] = 0; - x->mbmi_ext->compound_mode_context[ref_frame] = 0; mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX; - if (cpi->ref_frame_flags & ref_frame_flag_list[ref_frame]) { + if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) { if (mbmi->partition != PARTITION_NONE && mbmi->partition != PARTITION_SPLIT) { if (skip_ref_frame_mask & (1 << ref_frame)) { @@ -11051,8 +11419,8 @@ static void set_params_rd_pick_inter_mode( x->mbmi_ext->mode_context[ref_frame] = 0; mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX; const MV_REFERENCE_FRAME *rf = ref_frame_map[ref_frame - REF_FRAMES]; - if (!((cpi->ref_frame_flags & ref_frame_flag_list[rf[0]]) && - (cpi->ref_frame_flags & ref_frame_flag_list[rf[1]]))) { + if (!((cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[0]]) && + (cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[1]]))) { continue; } @@ -11087,7 +11455,8 @@ static void set_params_rd_pick_inter_mode( init_mode_skip_mask(mode_skip_mask, cpi, x, bsize); - if (cpi->sf.tx_type_search.fast_intra_tx_type_search) + if (cpi->sf.tx_type_search.fast_intra_tx_type_search || + cpi->oxcf.use_intra_default_tx_only) x->use_default_intra_tx_type = 1; else x->use_default_intra_tx_type = 0; @@ -11103,6 +11472,119 @@ static void set_params_rd_pick_inter_mode( x->comp_rd_stats_idx = 0; } +// TODO(kyslov): now this is very similar to set_params_rd_pick_inter_mode +// (except that doesn't set ALTREF parameters) +// consider passing a flag to select non-rd path (similar to +// encode_sb_row) +static void set_params_nonrd_pick_inter_mode( + const AV1_COMP *cpi, MACROBLOCK *x, HandleInterModeArgs *args, + BLOCK_SIZE bsize, int mi_row, int mi_col, mode_skip_mask_t *mode_skip_mask, + int skip_ref_frame_mask, unsigned int ref_costs_single[REF_FRAMES], + unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES], + struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) { + const AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; + unsigned char segment_id = mbmi->segment_id; + int dst_width1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE }; + int dst_width2[MAX_MB_PLANE] = { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1, + MAX_SB_SIZE >> 1 }; + int dst_height1[MAX_MB_PLANE] = { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1, + MAX_SB_SIZE >> 1 }; + int dst_height2[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE }; + + for (int i = 0; i < MB_MODE_COUNT; ++i) + for (int k = 0; k < REF_FRAMES; ++k) args->single_filter[i][k] = SWITCHABLE; + + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { + int len = sizeof(uint16_t); + args->above_pred_buf[0] = CONVERT_TO_BYTEPTR(x->above_pred_buf); + args->above_pred_buf[1] = + CONVERT_TO_BYTEPTR(x->above_pred_buf + (MAX_SB_SQUARE >> 1) * len); + args->above_pred_buf[2] = + CONVERT_TO_BYTEPTR(x->above_pred_buf + MAX_SB_SQUARE * len); + args->left_pred_buf[0] = CONVERT_TO_BYTEPTR(x->left_pred_buf); + args->left_pred_buf[1] = + CONVERT_TO_BYTEPTR(x->left_pred_buf + (MAX_SB_SQUARE >> 1) * len); + args->left_pred_buf[2] = + CONVERT_TO_BYTEPTR(x->left_pred_buf + MAX_SB_SQUARE * len); + } else { + args->above_pred_buf[0] = x->above_pred_buf; + args->above_pred_buf[1] = x->above_pred_buf + (MAX_SB_SQUARE >> 1); + args->above_pred_buf[2] = x->above_pred_buf + MAX_SB_SQUARE; + args->left_pred_buf[0] = x->left_pred_buf; + args->left_pred_buf[1] = x->left_pred_buf + (MAX_SB_SQUARE >> 1); + args->left_pred_buf[2] = x->left_pred_buf + MAX_SB_SQUARE; + } + + av1_collect_neighbors_ref_counts(xd); + + estimate_ref_frame_costs(cm, xd, x, segment_id, ref_costs_single, + ref_costs_comp); + + MV_REFERENCE_FRAME ref_frame; + for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + x->pred_mv_sad[ref_frame] = INT_MAX; + x->mbmi_ext->mode_context[ref_frame] = 0; + mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX; + if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) { + if (mbmi->partition != PARTITION_NONE && + mbmi->partition != PARTITION_SPLIT) { + if (skip_ref_frame_mask & (1 << ref_frame)) { + int skip = 1; + for (int r = ALTREF_FRAME + 1; r < MODE_CTX_REF_FRAMES; ++r) { + if (!(skip_ref_frame_mask & (1 << r))) { + const MV_REFERENCE_FRAME *rf = ref_frame_map[r - REF_FRAMES]; + if (rf[0] == ref_frame || rf[1] == ref_frame) { + skip = 0; + break; + } + } + } + if (skip) continue; + } + } + assert(get_ref_frame_yv12_buf(cm, ref_frame) != NULL); + setup_buffer_ref_mvs_inter(cpi, x, ref_frame, bsize, mi_row, mi_col, + yv12_mb); + } + } + av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col); + + if (check_num_overlappable_neighbors(mbmi) && + is_motion_variation_allowed_bsize(bsize)) { + av1_build_prediction_by_above_preds(cm, xd, mi_row, mi_col, + args->above_pred_buf, dst_width1, + dst_height1, args->above_pred_stride); + av1_build_prediction_by_left_preds(cm, xd, mi_row, mi_col, + args->left_pred_buf, dst_width2, + dst_height2, args->left_pred_stride); + av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row, mi_col, + 0, num_planes); + calc_target_weighted_pred( + cm, x, xd, mi_row, mi_col, args->above_pred_buf[0], + args->above_pred_stride[0], args->left_pred_buf[0], + args->left_pred_stride[0]); + } + init_mode_skip_mask(mode_skip_mask, cpi, x, bsize); + + if (cpi->sf.tx_type_search.fast_intra_tx_type_search) + x->use_default_intra_tx_type = 1; + else + x->use_default_intra_tx_type = 0; + + if (cpi->sf.tx_type_search.fast_inter_tx_type_search) + x->use_default_inter_tx_type = 1; + else + x->use_default_inter_tx_type = 0; + if (cpi->sf.skip_repeat_interpolation_filter_search) { + x->interp_filter_stats_idx[0] = 0; + x->interp_filter_stats_idx[1] = 0; + } +} + static void search_palette_mode(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, RD_STATS *rd_cost, PICK_MODE_CONTEXT *ctx, BLOCK_SIZE bsize, @@ -11178,9 +11660,6 @@ static void search_palette_mode(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, rate2 -= rd_stats_y.rate; if (num_planes > 1) rate2 -= search_state->rate_uv_tokenonly[uv_tx]; rate2 += x->skip_cost[av1_get_skip_context(xd)][1]; -#if CONFIG_ONE_PASS_SVM - av1_reg_stat_skipmode_update(&rd_stats_y, x->rdmult); -#endif } else { rate2 += x->skip_cost[av1_get_skip_context(xd)][0]; } @@ -11197,9 +11676,6 @@ static void search_palette_mode(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, search_state->best_mode_skippable = skippable; memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); -#if CONFIG_ONE_PASS_SVM - av1_copy_reg_stat(rd_cost, &rd_stats_y); -#endif } } @@ -11297,12 +11773,11 @@ static void init_inter_mode_search_state(InterModeSearchState *search_state, bool mask_says_skip(const mode_skip_mask_t *mode_skip_mask, const MV_REFERENCE_FRAME *ref_frame, const PREDICTION_MODE this_mode) { - if (mode_skip_mask->mode[ref_frame[0]] & (1 << this_mode)) { + if (mode_skip_mask->pred_modes[ref_frame[0]] & (1 << this_mode)) { return true; } - return (mode_skip_mask->ref_frame1 & (1 << ref_frame[0])) && - (mode_skip_mask->ref_frame2 & (1 << AOMMAX(0, ref_frame[1]))); + return mode_skip_mask->ref_combo[ref_frame[0]][ref_frame[1] + 1]; } static int inter_mode_compatible_skip(const AV1_COMP *cpi, const MACROBLOCK *x, @@ -11323,7 +11798,8 @@ static int inter_mode_compatible_skip(const AV1_COMP *cpi, const MACROBLOCK *x, if (current_frame->reference_mode == SINGLE_REFERENCE) return 1; // Skip compound inter modes if ARF is not available. - if (!(cpi->ref_frame_flags & ref_frame_flag_list[ref_frame[1]])) return 1; + if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame[1]])) + return 1; // Do not allow compound prediction if the segment level reference frame // feature is in use as in this case there can only be one reference. @@ -11333,7 +11809,7 @@ static int inter_mode_compatible_skip(const AV1_COMP *cpi, const MACROBLOCK *x, } if (ref_frame[0] > INTRA_FRAME && ref_frame[1] == INTRA_FRAME) { - // Mode must by compatible + // Mode must be compatible if (!is_interintra_allowed_mode(this_mode)) return 1; if (!is_interintra_allowed_bsize(bsize)) return 1; } @@ -11341,13 +11817,30 @@ static int inter_mode_compatible_skip(const AV1_COMP *cpi, const MACROBLOCK *x, return 0; } +static int fetch_picked_ref_frames_mask(const MACROBLOCK *const x, + BLOCK_SIZE bsize, int mib_size, + int mi_row, int mi_col) { + const int sb_size_mask = mib_size - 1; + const int mi_row_in_sb = mi_row & sb_size_mask; + const int mi_col_in_sb = mi_col & sb_size_mask; + const int mi_w = mi_size_wide[bsize]; + const int mi_h = mi_size_high[bsize]; + int picked_ref_frames_mask = 0; + for (int i = mi_row_in_sb; i < mi_row_in_sb + mi_h; ++i) { + for (int j = mi_col_in_sb; j < mi_col_in_sb + mi_w; ++j) { + picked_ref_frames_mask |= x->picked_ref_frames_mask[i * 32 + j]; + } + } + return picked_ref_frames_mask; +} + // Case 1: return 0, means don't skip this mode // Case 2: return 1, means skip this mode completely // Case 3: return 2, means skip compound only, but still try single motion modes static int inter_mode_search_order_independent_skip( - const AV1_COMP *cpi, const PICK_MODE_CONTEXT *ctx, const MACROBLOCK *x, - BLOCK_SIZE bsize, int mode_index, int mi_row, int mi_col, - mode_skip_mask_t *mode_skip_mask, InterModeSearchState *search_state) { + const AV1_COMP *cpi, const MACROBLOCK *x, BLOCK_SIZE bsize, int mode_index, + int mi_row, int mi_col, mode_skip_mask_t *mode_skip_mask, + InterModeSearchState *search_state, int skip_ref_frame_mask) { const SPEED_FEATURES *const sf = &cpi->sf; const AV1_COMMON *const cm = &cpi->common; const OrderHintInfo *const order_hint_info = &cm->seq_params.order_hint_info; @@ -11371,14 +11864,14 @@ static int inter_mode_search_order_independent_skip( if (mbmi->partition != PARTITION_NONE && mbmi->partition != PARTITION_SPLIT) { const int ref_type = av1_ref_frame_type(ref_frame); - int skip_ref = ctx->skip_ref_frame_mask & (1 << ref_type); + int skip_ref = skip_ref_frame_mask & (1 << ref_type); if (ref_type <= ALTREF_FRAME && skip_ref) { // Since the compound ref modes depends on the motion estimation result of // two single ref modes( best mv of single ref modes as the start point ) // If current single ref mode is marked skip, we need to check if it will // be used in compound ref modes. for (int r = ALTREF_FRAME + 1; r < MODE_CTX_REF_FRAMES; ++r) { - if (!(ctx->skip_ref_frame_mask & (1 << r))) { + if (!(skip_ref_frame_mask & (1 << r))) { const MV_REFERENCE_FRAME *rf = ref_frame_map[r - REF_FRAMES]; if (rf[0] == ref_type || rf[1] == ref_type) { // Found a not skipped compound ref mode which contains current @@ -11395,8 +11888,7 @@ static int inter_mode_search_order_independent_skip( if (skip_ref) return 1; } - if (cpi->sf.mode_pruning_based_on_two_pass_partition_search && - !x->cb_partition_scan) { + if (cpi->two_pass_partition_search && !x->cb_partition_scan) { const int mi_width = mi_size_wide[bsize]; const int mi_height = mi_size_high[bsize]; int found = 0; @@ -11491,7 +11983,7 @@ static int inter_mode_search_order_independent_skip( // Check if one of the reference is ALTREF2_FRAME and BWDREF_FRAME is a // valid reference. if ((ref_frame[0] == ALTREF2_FRAME || ref_frame[1] == ALTREF2_FRAME) && - (cpi->ref_frame_flags & ref_frame_flag_list[BWDREF_FRAME])) { + (cpi->ref_frame_flags & av1_ref_frame_flag_list[BWDREF_FRAME])) { // Check if both ALTREF2_FRAME and BWDREF_FRAME are future references. if ((get_relative_dist( order_hint_info, @@ -11514,7 +12006,6 @@ static int inter_mode_search_order_independent_skip( const RefCntBuffer *const buf_bwd = get_ref_frame_buf(cm, BWDREF_FRAME); assert(buf_bwd != NULL); - assert(buf_arf2->frame_rf_level == buf_bwd->frame_rf_level); (void)buf_arf2; (void)buf_bwd; return 1; @@ -11529,6 +12020,16 @@ static int inter_mode_search_order_independent_skip( if (skip_motion_mode) { return 2; } + + if (!cpi->oxcf.enable_global_motion && + (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV)) { + return 1; + } + + if (!cpi->oxcf.enable_onesided_comp && comp_pred && cpi->all_one_sided_refs) { + return 1; + } + return 0; } @@ -11564,6 +12065,7 @@ static int64_t handle_intra_mode(InterModeSearchState *search_state, assert(mbmi->ref_frame[0] == INTRA_FRAME); PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; const int try_palette = + cpi->oxcf.enable_palette && av1_allow_palette(cm->allow_screen_content_tools, mbmi->sb_type); const int *const intra_mode_cost = x->mbmode_cost[size_group_lookup[bsize]]; const int intra_cost_penalty = av1_get_intra_cost_penalty( @@ -12126,6 +12628,16 @@ static void release_compound_type_rd_buffers( av1_zero(*bufs); // Set all pointers to NULL for safety. } +// Enables do_tx_search on a per-mode basis. +int do_tx_search_mode(int do_tx_search_global, int midx, int adaptive) { + if (!adaptive || do_tx_search_global) { + return do_tx_search_global; + } + // A value of 2 indicates it is being turned on conditionally + // for the mode. Turn it on for the first 7 modes. + return midx < 7 ? 2 : 0; +} + void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x, int mi_row, int mi_col, RD_STATS *rd_cost, BLOCK_SIZE bsize, @@ -12149,12 +12661,6 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, int *comp_inter_cost = x->comp_inter_cost[av1_get_reference_mode_context(xd)]; mode_skip_mask_t mode_skip_mask; uint8_t motion_mode_skip_mask = 0; // second pass of single ref modes -#if CONFIG_ONE_PASS_SVM - int temp_y_eob = 0, temp_y_eob_0 = 0, temp_y_eob_1 = 0, temp_y_eob_2 = 0, - temp_y_eob_3 = 0; - int64_t temp_y_rd = 0, temp_y_rd_0 = 0, temp_y_rd_1 = 0, temp_y_rd_2 = 0, - temp_y_rd_3 = 0; -#endif InterModeSearchState search_state; init_inter_mode_search_state(&search_state, cpi, tile_data, x, bsize, @@ -12177,15 +12683,37 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, av1_invalid_rd_stats(rd_cost); + // Ref frames that are selected by square partition blocks. + int picked_ref_frames_mask = 0; + if (cpi->sf.prune_ref_frame_for_rect_partitions && + mbmi->partition != PARTITION_NONE && mbmi->partition != PARTITION_SPLIT) { + // prune_ref_frame_for_rect_partitions = 1 implies prune only extended + // partition blocks. prune_ref_frame_for_rect_partitions >=2 + // implies prune for vert, horiz and extended partition blocks. + if ((mbmi->partition != PARTITION_VERT && + mbmi->partition != PARTITION_HORZ) || + cpi->sf.prune_ref_frame_for_rect_partitions >= 2) { + picked_ref_frames_mask = fetch_picked_ref_frames_mask( + x, bsize, cm->seq_params.mib_size, mi_row, mi_col); + } + } + + // Skip ref frames that never selected by square blocks. + const int skip_ref_frame_mask = + picked_ref_frames_mask ? ~picked_ref_frames_mask : 0; + // init params, set frame modes, speed features set_params_rd_pick_inter_mode(cpi, x, &args, bsize, mi_row, mi_col, - &mode_skip_mask, ctx->skip_ref_frame_mask, + &mode_skip_mask, skip_ref_frame_mask, ref_costs_single, ref_costs_comp, yv12_mb); int64_t best_est_rd = INT64_MAX; // TODO(angiebird): Turn this on when this speed feature is well tested const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize]; - const int do_tx_search = + // If do_tx_search_global is 0, only estimated RD should be computed. + // If do_tx_search_global is 1, all modes have TX search performed. + // If do_tx_search_global is 2, some modes will have TX search performed. + const int do_tx_search_global = !((cpi->sf.inter_mode_rd_model_estimation == 1 && md->ready) || (cpi->sf.inter_mode_rd_model_estimation == 2 && x->source_variance < 512)); @@ -12203,6 +12731,8 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, alloc_compound_type_rd_buffers(cm, &rd_buffers); for (int midx = 0; midx < MAX_MODES; ++midx) { + const int do_tx_search = do_tx_search_mode( + do_tx_search_global, midx, sf->inter_mode_rd_model_estimation_adaptive); const MODE_DEFINITION *mode_order = &av1_mode_order[midx]; this_mode = mode_order->mode; const MV_REFERENCE_FRAME ref_frame = mode_order->ref_frame[0]; @@ -12257,8 +12787,570 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (inter_mode_compatible_skip(cpi, x, bsize, midx)) continue; const int ret = inter_mode_search_order_independent_skip( - cpi, ctx, x, bsize, midx, mi_row, mi_col, &mode_skip_mask, - &search_state); + cpi, x, bsize, midx, mi_row, mi_col, &mode_skip_mask, &search_state, + skip_ref_frame_mask); + if (ret == 1) continue; + args.skip_motion_mode = (ret == 2); + + if (sf->drop_ref && comp_pred) { + if (sf_check_is_drop_ref(mode_order, &search_state)) { + continue; + } + } + + if (search_state.best_rd < search_state.mode_threshold[midx]) continue; + + if (sf->prune_comp_search_by_single_result > 0 && comp_pred) { + if (compound_skip_by_single_states(cpi, &search_state, this_mode, + ref_frame, second_ref_frame, x)) + continue; + } + + const int ref_frame_cost = comp_pred + ? ref_costs_comp[ref_frame][second_ref_frame] + : ref_costs_single[ref_frame]; + const int compmode_cost = + is_comp_ref_allowed(mbmi->sb_type) ? comp_inter_cost[comp_pred] : 0; + const int real_compmode_cost = + cm->current_frame.reference_mode == REFERENCE_MODE_SELECT + ? compmode_cost + : 0; + + if (comp_pred) { + if ((sf->mode_search_skip_flags & FLAG_SKIP_COMP_BESTINTRA) && + search_state.best_mode_index >= 0 && + search_state.best_mbmode.ref_frame[0] == INTRA_FRAME) + continue; + } + + if (ref_frame == INTRA_FRAME) { + if ((!cpi->oxcf.enable_smooth_intra || sf->disable_smooth_intra) && + (mbmi->mode == SMOOTH_PRED || mbmi->mode == SMOOTH_H_PRED || + mbmi->mode == SMOOTH_V_PRED)) + continue; + if (!cpi->oxcf.enable_paeth_intra && mbmi->mode == PAETH_PRED) continue; + if (sf->adaptive_mode_search > 1) + if ((x->source_variance << num_pels_log2_lookup[bsize]) > + search_state.best_pred_sse) + continue; + + if (this_mode != DC_PRED) { + // Only search the oblique modes if the best so far is + // one of the neighboring directional modes + if ((sf->mode_search_skip_flags & FLAG_SKIP_INTRA_BESTINTER) && + (this_mode >= D45_PRED && this_mode <= PAETH_PRED)) { + if (search_state.best_mode_index >= 0 && + search_state.best_mbmode.ref_frame[0] > INTRA_FRAME) + continue; + } + if (sf->mode_search_skip_flags & FLAG_SKIP_INTRA_DIRMISMATCH) { + if (conditional_skipintra(this_mode, search_state.best_intra_mode)) + continue; + } + } + } + + // Select prediction reference frames. + for (i = 0; i < num_planes; i++) { + xd->plane[i].pre[0] = yv12_mb[ref_frame][i]; + if (comp_pred) xd->plane[i].pre[1] = yv12_mb[second_ref_frame][i]; + } + + if (ref_frame == INTRA_FRAME) { + intra_mode_idx_ls[intra_mode_num++] = midx; + continue; + } else { + mbmi->angle_delta[PLANE_TYPE_Y] = 0; + mbmi->angle_delta[PLANE_TYPE_UV] = 0; + mbmi->filter_intra_mode_info.use_filter_intra = 0; + mbmi->ref_mv_idx = 0; + int64_t ref_best_rd = search_state.best_rd; + { + RD_STATS rd_stats, rd_stats_y, rd_stats_uv; + av1_init_rd_stats(&rd_stats); + rd_stats.rate = rate2; + + // Point to variables that are maintained between loop iterations + args.single_newmv = search_state.single_newmv; + args.single_newmv_rate = search_state.single_newmv_rate; + args.single_newmv_valid = search_state.single_newmv_valid; + args.single_comp_cost = real_compmode_cost; + args.ref_frame_cost = ref_frame_cost; + if (midx < MAX_SINGLE_REF_MODES) { + args.simple_rd_state = x->simple_rd_state[midx]; + } + +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, handle_inter_mode_time); +#endif + this_rd = handle_inter_mode( + cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, + &disable_skip, mi_row, mi_col, &args, ref_best_rd, tmp_buf, + &rd_buffers, &best_est_rd, do_tx_search, inter_modes_info); +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, handle_inter_mode_time); +#endif + rate2 = rd_stats.rate; + skippable = rd_stats.skip; + distortion2 = rd_stats.dist; + rate_y = rd_stats_y.rate; + rate_uv = rd_stats_uv.rate; + } + + if (sf->prune_comp_search_by_single_result > 0 && + is_inter_singleref_mode(this_mode) && args.single_ref_first_pass) { + collect_single_states(x, &search_state, mbmi); + } + + if (this_rd == INT64_MAX) continue; + + this_skip2 = mbmi->skip; + this_rd = RDCOST(x->rdmult, rate2, distortion2); + if (this_skip2) { + rate_y = 0; + rate_uv = 0; + } + } + + // Did this mode help.. i.e. is it the new best mode + if (this_rd < search_state.best_rd || x->skip) { + int mode_excluded = 0; + if (comp_pred) { + mode_excluded = cm->current_frame.reference_mode == SINGLE_REFERENCE; + } + if (!mode_excluded) { + // Note index of best mode so far + search_state.best_mode_index = midx; + + if (ref_frame == INTRA_FRAME) { + /* required for left and above block mv */ + mbmi->mv[0].as_int = 0; + } else { + search_state.best_pred_sse = x->pred_sse[ref_frame]; + } + + rd_cost->rate = rate2; + rd_cost->dist = distortion2; + rd_cost->rdcost = this_rd; + search_state.best_rd = this_rd; + search_state.best_mbmode = *mbmi; + search_state.best_skip2 = this_skip2; + search_state.best_mode_skippable = skippable; + if (do_tx_search) { + // When do_tx_search == 0, handle_inter_mode won't provide correct + // rate_y and rate_uv because txfm_search process is replaced by + // rd estimation. + // Therfore, we should avoid updating best_rate_y and best_rate_uv + // here. These two values will be updated when txfm_search is called + search_state.best_rate_y = + rate_y + + x->skip_cost[av1_get_skip_context(xd)][this_skip2 || skippable]; + search_state.best_rate_uv = rate_uv; + } + memcpy(ctx->blk_skip, x->blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + } + } + + /* keep record of best compound/single-only prediction */ + if (!disable_skip && ref_frame != INTRA_FRAME) { + int64_t single_rd, hybrid_rd, single_rate, hybrid_rate; + + if (cm->current_frame.reference_mode == REFERENCE_MODE_SELECT) { + single_rate = rate2 - compmode_cost; + hybrid_rate = rate2; + } else { + single_rate = rate2; + hybrid_rate = rate2 + compmode_cost; + } + + single_rd = RDCOST(x->rdmult, single_rate, distortion2); + hybrid_rd = RDCOST(x->rdmult, hybrid_rate, distortion2); + + if (!comp_pred) { + if (single_rd < search_state.best_pred_rd[SINGLE_REFERENCE]) + search_state.best_pred_rd[SINGLE_REFERENCE] = single_rd; + } else { + if (single_rd < search_state.best_pred_rd[COMPOUND_REFERENCE]) + search_state.best_pred_rd[COMPOUND_REFERENCE] = single_rd; + } + if (hybrid_rd < search_state.best_pred_rd[REFERENCE_MODE_SELECT]) + search_state.best_pred_rd[REFERENCE_MODE_SELECT] = hybrid_rd; + } + if (sf->drop_ref && second_ref_frame == NONE_FRAME) { + // Collect data from single ref mode, and analyze data. + sf_drop_ref_analyze(&search_state, mode_order, distortion2); + } + + if (x->skip && !comp_pred) break; + } + + release_compound_type_rd_buffers(&rd_buffers); + +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, do_tx_search_time); +#endif + if (do_tx_search_global != 1) { + inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr); + search_state.best_rd = INT64_MAX; + + int64_t top_est_rd = + inter_modes_info->num > 0 + ? inter_modes_info + ->est_rd_arr[inter_modes_info->rd_idx_pair_arr[0].idx] + : INT64_MAX; + for (int j = 0; j < inter_modes_info->num; ++j) { + const int data_idx = inter_modes_info->rd_idx_pair_arr[j].idx; + *mbmi = inter_modes_info->mbmi_arr[data_idx]; + int64_t curr_est_rd = inter_modes_info->est_rd_arr[data_idx]; + if (curr_est_rd * 0.80 > top_est_rd) break; + + RD_STATS rd_stats; + RD_STATS rd_stats_y; + RD_STATS rd_stats_uv; + + bool true_rd = inter_modes_info->true_rd_arr[data_idx]; + if (true_rd) { + rd_stats = inter_modes_info->rd_cost_arr[data_idx]; + rd_stats_y = inter_modes_info->rd_cost_y_arr[data_idx]; + rd_stats_uv = inter_modes_info->rd_cost_uv_arr[data_idx]; + memcpy(x->blk_skip, inter_modes_info->blk_skip_arr[data_idx], + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + } else { + const int mode_rate = inter_modes_info->mode_rate_arr[data_idx]; + + x->skip = 0; + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + + // Select prediction reference frames. + const int is_comp_pred = mbmi->ref_frame[1] > INTRA_FRAME; + for (i = 0; i < num_planes; i++) { + xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i]; + if (is_comp_pred) + xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; + } + + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0, + av1_num_planes(cm) - 1); + if (mbmi->motion_mode == OBMC_CAUSAL) + av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); + + if (!txfm_search(cpi, tile_data, x, bsize, mi_row, mi_col, &rd_stats, + &rd_stats_y, &rd_stats_uv, mode_rate, + search_state.best_rd)) { + continue; + } else if (cpi->sf.inter_mode_rd_model_estimation == 1) { + const int skip_ctx = av1_get_skip_context(xd); + inter_mode_data_push(tile_data, mbmi->sb_type, rd_stats.sse, + rd_stats.dist, + rd_stats_y.rate + rd_stats_uv.rate + + x->skip_cost[skip_ctx][mbmi->skip]); + } + rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist); + } + + if (rd_stats.rdcost < search_state.best_rd) { + search_state.best_rd = rd_stats.rdcost; + // Note index of best mode so far + const int mode_index = get_prediction_mode_idx( + mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); + search_state.best_mode_index = mode_index; + *rd_cost = rd_stats; + search_state.best_rd = rd_stats.rdcost; + search_state.best_mbmode = *mbmi; + search_state.best_skip2 = mbmi->skip; + search_state.best_mode_skippable = rd_stats.skip; + search_state.best_rate_y = + rd_stats_y.rate + + x->skip_cost[av1_get_skip_context(xd)][rd_stats.skip || mbmi->skip]; + search_state.best_rate_uv = rd_stats_uv.rate; + memcpy(ctx->blk_skip, x->blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + } + } + } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, do_tx_search_time); +#endif + +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, handle_intra_mode_time); +#endif + for (int j = 0; j < intra_mode_num; ++j) { + const int mode_index = intra_mode_idx_ls[j]; + const MV_REFERENCE_FRAME ref_frame = + av1_mode_order[mode_index].ref_frame[0]; + assert(av1_mode_order[mode_index].ref_frame[1] == NONE_FRAME); + assert(ref_frame == INTRA_FRAME); + if (sf->skip_intra_in_interframe && search_state.skip_intra_modes) break; + init_mbmi(mbmi, mode_index, cm); + x->skip = 0; + set_ref_ptrs(cm, xd, INTRA_FRAME, NONE_FRAME); + + // Select prediction reference frames. + for (i = 0; i < num_planes; i++) { + xd->plane[i].pre[0] = yv12_mb[ref_frame][i]; + } + + RD_STATS intra_rd_stats, intra_rd_stats_y, intra_rd_stats_uv; + + const int ref_frame_cost = ref_costs_single[ref_frame]; + intra_rd_stats.rdcost = handle_intra_mode( + &search_state, cpi, x, bsize, mi_row, mi_col, ref_frame_cost, ctx, 0, + &intra_rd_stats, &intra_rd_stats_y, &intra_rd_stats_uv); + if (intra_rd_stats.rdcost < search_state.best_rd) { + search_state.best_rd = intra_rd_stats.rdcost; + // Note index of best mode so far + search_state.best_mode_index = mode_index; + *rd_cost = intra_rd_stats; + search_state.best_rd = intra_rd_stats.rdcost; + search_state.best_mbmode = *mbmi; + search_state.best_skip2 = 0; + search_state.best_mode_skippable = intra_rd_stats.skip; + search_state.best_rate_y = + intra_rd_stats_y.rate + + x->skip_cost[av1_get_skip_context(xd)][intra_rd_stats.skip]; + search_state.best_rate_uv = intra_rd_stats_uv.rate; + memcpy(ctx->blk_skip, x->blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + } + } +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, handle_intra_mode_time); +#endif + + // In effect only when speed >= 2. + sf_refine_fast_tx_type_search( + cpi, x, mi_row, mi_col, rd_cost, bsize, ctx, search_state.best_mode_index, + &search_state.best_mbmode, yv12_mb, search_state.best_rate_y, + search_state.best_rate_uv, &search_state.best_skip2); + + // Only try palette mode when the best mode so far is an intra mode. + if (try_palette && !is_inter_mode(search_state.best_mbmode.mode)) { + search_palette_mode(cpi, x, mi_row, mi_col, rd_cost, ctx, bsize, mbmi, pmi, + ref_costs_single, &search_state); + } + search_state.best_mbmode.skip_mode = 0; + if (cm->current_frame.skip_mode_info.skip_mode_flag && + !segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) && + is_comp_ref_allowed(bsize)) { + rd_pick_skip_mode(rd_cost, &search_state, cpi, x, bsize, mi_row, mi_col, + yv12_mb); + } + + // Make sure that the ref_mv_idx is only nonzero when we're + // using a mode which can support ref_mv_idx + if (search_state.best_mbmode.ref_mv_idx != 0 && + !(search_state.best_mbmode.mode == NEWMV || + search_state.best_mbmode.mode == NEW_NEWMV || + have_nearmv_in_inter_mode(search_state.best_mbmode.mode))) { + search_state.best_mbmode.ref_mv_idx = 0; + } + + if (search_state.best_mode_index < 0 || + search_state.best_rd >= best_rd_so_far) { + rd_cost->rate = INT_MAX; + rd_cost->rdcost = INT64_MAX; + return; + } + + assert( + (cm->interp_filter == SWITCHABLE) || + (cm->interp_filter == + av1_extract_interp_filter(search_state.best_mbmode.interp_filters, 0)) || + !is_inter_block(&search_state.best_mbmode)); + assert( + (cm->interp_filter == SWITCHABLE) || + (cm->interp_filter == + av1_extract_interp_filter(search_state.best_mbmode.interp_filters, 1)) || + !is_inter_block(&search_state.best_mbmode)); + + if (!cpi->rc.is_src_frame_alt_ref) + av1_update_rd_thresh_fact(cm, tile_data->thresh_freq_fact, + sf->adaptive_rd_thresh, bsize, + search_state.best_mode_index); + + // macroblock modes + *mbmi = search_state.best_mbmode; + x->skip |= search_state.best_skip2; + + // Note: this section is needed since the mode may have been forced to + // GLOBALMV by the all-zero mode handling of ref-mv. + if (mbmi->mode == GLOBALMV || mbmi->mode == GLOBAL_GLOBALMV) { + // Correct the interp filters for GLOBALMV + if (is_nontrans_global_motion(xd, xd->mi[0])) { + assert(mbmi->interp_filters == + av1_broadcast_interp_filter( + av1_unswitchable_filter(cm->interp_filter))); + } + } + + for (i = 0; i < REFERENCE_MODES; ++i) { + if (search_state.best_pred_rd[i] == INT64_MAX) + search_state.best_pred_diff[i] = INT_MIN; + else + search_state.best_pred_diff[i] = + search_state.best_rd - search_state.best_pred_rd[i]; + } + + x->skip |= search_state.best_mode_skippable; + + assert(search_state.best_mode_index >= 0); + + store_coding_context(x, ctx, search_state.best_mode_index, + search_state.best_pred_diff, + search_state.best_mode_skippable); + + if (pmi->palette_size[1] > 0) { + assert(try_palette); + restore_uv_color_map(cpi, x); + } +} + +// TODO(kyslov): now this is very similar to av1_rd_pick_inter_mode_sb except: +// it only checks non-compound mode and +// it doesn't check palette mode +// it doesn't refine tx search +// this function is likely to be heavily modified with nonrd mode +// decision +void av1_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, + MACROBLOCK *x, int mi_row, int mi_col, + RD_STATS *rd_cost, BLOCK_SIZE bsize, + PICK_MODE_CONTEXT *ctx, + int64_t best_rd_so_far) { + AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + const SPEED_FEATURES *const sf = &cpi->sf; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const struct segmentation *const seg = &cm->seg; + PREDICTION_MODE this_mode; + unsigned char segment_id = mbmi->segment_id; + int i; + struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]; + unsigned int ref_costs_single[REF_FRAMES]; + unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES]; + int *comp_inter_cost = x->comp_inter_cost[av1_get_reference_mode_context(xd)]; + mode_skip_mask_t mode_skip_mask; + uint8_t motion_mode_skip_mask = 0; // second pass of single ref modes + + InterModeSearchState search_state; + init_inter_mode_search_state(&search_state, cpi, tile_data, x, bsize, + best_rd_so_far); + INTERINTRA_MODE interintra_modes[REF_FRAMES] = { + INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, + INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES + }; + HandleInterModeArgs args = { + { NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE }, + { NULL }, { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1 }, + NULL, NULL, + NULL, search_state.modelled_rd, + { { 0 } }, INT_MAX, + INT_MAX, search_state.simple_rd, + 0, interintra_modes, + 1, NULL + }; + for (i = 0; i < REF_FRAMES; ++i) x->pred_sse[i] = INT_MAX; + + av1_invalid_rd_stats(rd_cost); + + // Ref frames that are selected by square partition blocks. + int picked_ref_frames_mask = 0; + if (cpi->sf.prune_ref_frame_for_rect_partitions && + mbmi->partition != PARTITION_NONE && mbmi->partition != PARTITION_SPLIT) { + // Don't enable for vert and horz partition blocks if current frame + // will be used as bwd or arf2. + if ((!cpi->refresh_bwd_ref_frame && !cpi->refresh_alt2_ref_frame) || + (mbmi->partition != PARTITION_VERT && + mbmi->partition != PARTITION_HORZ)) { + picked_ref_frames_mask = fetch_picked_ref_frames_mask( + x, bsize, cm->seq_params.mib_size, mi_row, mi_col); + } + } + + // Skip ref frames that never selected by square blocks. + const int skip_ref_frame_mask = + picked_ref_frames_mask ? ~picked_ref_frames_mask : 0; + + // init params, set frame modes, speed features + set_params_nonrd_pick_inter_mode(cpi, x, &args, bsize, mi_row, mi_col, + &mode_skip_mask, skip_ref_frame_mask, + ref_costs_single, ref_costs_comp, yv12_mb); + + int64_t best_est_rd = INT64_MAX; + InterModesInfo *inter_modes_info = x->inter_modes_info; + inter_modes_info->num = 0; + + int intra_mode_num = 0; + int intra_mode_idx_ls[MAX_MODES]; + int reach_first_comp_mode = 0; + + // Temporary buffers used by handle_inter_mode(). + uint8_t *const tmp_buf = get_buf_by_bd(xd, x->tmp_obmc_bufs[0]); + + CompoundTypeRdBuffers rd_buffers; + alloc_compound_type_rd_buffers(cm, &rd_buffers); + + for (int midx = 0; midx < MAX_MODES; ++midx) { + const MODE_DEFINITION *mode_order = &av1_mode_order[midx]; + this_mode = mode_order->mode; + const MV_REFERENCE_FRAME ref_frame = mode_order->ref_frame[0]; + const MV_REFERENCE_FRAME second_ref_frame = mode_order->ref_frame[1]; + const int comp_pred = second_ref_frame > INTRA_FRAME; + + if (second_ref_frame != NONE_FRAME) continue; + + // When single ref motion search ends: + // 1st pass: To evaluate single ref RD results and rewind to the beginning; + // 2nd pass: To continue with compound ref search. + if (sf->prune_single_motion_modes_by_simple_trans) { + if (comp_pred && args.single_ref_first_pass) { + args.single_ref_first_pass = 0; + // Reach the first comp ref mode + // Reset midx to start the 2nd pass for single ref motion search + midx = -1; + motion_mode_skip_mask = analyze_simple_trans_states(cpi, x); + continue; + } + if (!comp_pred && ref_frame != INTRA_FRAME) { // single ref mode + if (args.single_ref_first_pass) { + // clear stats + for (int k = 0; k < MAX_REF_MV_SERCH; ++k) { + x->simple_rd_state[midx][k].rd_stats.rdcost = INT64_MAX; + x->simple_rd_state[midx][k].early_skipped = 0; + } + } else { + if (motion_mode_skip_mask & (1 << ref_frame)) { + continue; + } + } + } + } + + // Reach the first compound prediction mode + if (sf->prune_comp_search_by_single_result > 0 && comp_pred && + reach_first_comp_mode == 0) { + analyze_single_states(cpi, &search_state); + reach_first_comp_mode = 1; + } + int64_t this_rd = INT64_MAX; + int disable_skip = 0; + int rate2 = 0; + int64_t distortion2 = 0; + int skippable = 0; + int this_skip2 = 0; + + init_mbmi(mbmi, midx, cm); + + x->skip = 0; + set_ref_ptrs(cm, xd, ref_frame, second_ref_frame); + + if (inter_mode_compatible_skip(cpi, x, bsize, midx)) continue; + + const int ret = inter_mode_search_order_independent_skip( + cpi, x, bsize, midx, mi_row, mi_col, &mode_skip_mask, &search_state, + skip_ref_frame_mask); if (ret == 1) continue; args.skip_motion_mode = (ret == 2); @@ -12352,18 +13444,10 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, this_rd = handle_inter_mode( cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, &disable_skip, mi_row, mi_col, &args, ref_best_rd, tmp_buf, - &rd_buffers, &best_est_rd, do_tx_search, inter_modes_info); + &rd_buffers, &best_est_rd, 0, inter_modes_info); rate2 = rd_stats.rate; skippable = rd_stats.skip; distortion2 = rd_stats.dist; - rate_y = rd_stats_y.rate; - rate_uv = rd_stats_uv.rate; -#if CONFIG_ONE_PASS_SVM - av1_unpack_reg_stat(&rd_stats_y, &temp_y_eob, &temp_y_eob_0, - &temp_y_eob_1, &temp_y_eob_2, &temp_y_eob_3, - &temp_y_rd, &temp_y_rd_0, &temp_y_rd_1, - &temp_y_rd_2, &temp_y_rd_3); -#endif } if (sf->prune_comp_search_by_single_result > 0 && @@ -12375,10 +13459,6 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, this_skip2 = mbmi->skip; this_rd = RDCOST(x->rdmult, rate2, distortion2); - if (this_skip2) { - rate_y = 0; - rate_uv = 0; - } } // Did this mode help.. i.e. is it the new best mode @@ -12405,23 +13485,6 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, search_state.best_mbmode = *mbmi; search_state.best_skip2 = this_skip2; search_state.best_mode_skippable = skippable; - if (do_tx_search) { - // When do_tx_search == 0, handle_inter_mode won't provide correct - // rate_y and rate_uv because txfm_search process is replaced by - // rd estimation. - // Therfore, we should avoid updating best_rate_y and best_rate_uv - // here. These two values will be updated when txfm_search is called - search_state.best_rate_y = - rate_y + - x->skip_cost[av1_get_skip_context(xd)][this_skip2 || skippable]; - search_state.best_rate_uv = rate_uv; - -#if CONFIG_ONE_PASS_SVM - av1_set_reg_stat(rd_cost, temp_y_eob, temp_y_eob_0, temp_y_eob_1, - temp_y_eob_2, temp_y_eob_3, temp_y_rd, temp_y_rd_0, - temp_y_rd_1, temp_y_rd_2, temp_y_rd_3); -#endif - } memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); } @@ -12462,47 +13525,37 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, release_compound_type_rd_buffers(&rd_buffers); - if (!do_tx_search) { - inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr); - search_state.best_rd = INT64_MAX; + inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr); + search_state.best_rd = INT64_MAX; - int64_t top_est_rd = - inter_modes_info->num > 0 - ? inter_modes_info - ->est_rd_arr[inter_modes_info->rd_idx_pair_arr[0].idx] - : INT64_MAX; - for (int j = 0; j < inter_modes_info->num; ++j) { - const int data_idx = inter_modes_info->rd_idx_pair_arr[j].idx; - *mbmi = inter_modes_info->mbmi_arr[data_idx]; - int64_t curr_est_rd = inter_modes_info->est_rd_arr[data_idx]; - if (curr_est_rd * 0.80 > top_est_rd) break; + if (inter_modes_info->num > 0) { + const int data_idx = inter_modes_info->rd_idx_pair_arr[0].idx; + *mbmi = inter_modes_info->mbmi_arr[data_idx]; + const int mode_rate = inter_modes_info->mode_rate_arr[data_idx]; - const int mode_rate = inter_modes_info->mode_rate_arr[data_idx]; + x->skip = 0; + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); - x->skip = 0; - set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + // Select prediction reference frames. + const int is_comp_pred = mbmi->ref_frame[1] > INTRA_FRAME; + for (i = 0; i < num_planes; i++) { + xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i]; + if (is_comp_pred) xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; + } - // Select prediction reference frames. - const int is_comp_pred = mbmi->ref_frame[1] > INTRA_FRAME; - for (i = 0; i < num_planes; i++) { - xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i]; - if (is_comp_pred) xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; - } + RD_STATS rd_stats; + RD_STATS rd_stats_y; + RD_STATS rd_stats_uv; - RD_STATS rd_stats; - RD_STATS rd_stats_y; - RD_STATS rd_stats_uv; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0, + av1_num_planes(cm) - 1); + if (mbmi->motion_mode == OBMC_CAUSAL) + av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0, - av1_num_planes(cm) - 1); - if (mbmi->motion_mode == OBMC_CAUSAL) - av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); - - if (!txfm_search(cpi, tile_data, x, bsize, mi_row, mi_col, &rd_stats, - &rd_stats_y, &rd_stats_uv, mode_rate, - search_state.best_rd)) { - continue; - } else if (cpi->sf.inter_mode_rd_model_estimation == 1) { + if (txfm_search(cpi, tile_data, x, bsize, mi_row, mi_col, &rd_stats, + &rd_stats_y, &rd_stats_uv, mode_rate, + search_state.best_rd)) { + if (cpi->sf.inter_mode_rd_model_estimation == 1) { const int skip_ctx = av1_get_skip_context(xd); inter_mode_data_push(tile_data, mbmi->sb_type, rd_stats.sse, rd_stats.dist, @@ -12528,9 +13581,6 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, search_state.best_rate_uv = rd_stats_uv.rate; memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); -#if CONFIG_ONE_PASS_SVM - av1_copy_reg_stat(rd_cost, &rd_stats_y); -#endif } } } @@ -12572,24 +13622,9 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, search_state.best_rate_uv = intra_rd_stats_uv.rate; memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); -#if CONFIG_ONE_PASS_SVM - av1_copy_reg_stat(rd_cost, &intra_rd_stats_y); -#endif } } - // In effect only when speed >= 2. - sf_refine_fast_tx_type_search( - cpi, x, mi_row, mi_col, rd_cost, bsize, ctx, search_state.best_mode_index, - &search_state.best_mbmode, yv12_mb, search_state.best_rate_y, - search_state.best_rate_uv, &search_state.best_skip2); - - // Only try palette mode when the best mode so far is an intra mode. - if (try_palette && !is_inter_mode(search_state.best_mbmode.mode)) { - search_palette_mode(cpi, x, mi_row, mi_col, rd_cost, ctx, bsize, mbmi, pmi, - ref_costs_single, &search_state); - } - search_state.best_mbmode.skip_mode = 0; if (cm->current_frame.skip_mode_info.skip_mode_flag && !segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) && @@ -12660,11 +13695,6 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, store_coding_context(x, ctx, search_state.best_mode_index, search_state.best_pred_diff, search_state.best_mode_skippable); - - if (pmi->palette_size[1] > 0) { - assert(try_palette); - restore_uv_color_map(cpi, x); - } } void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, @@ -13057,12 +14087,14 @@ void gaussian_blur(const uint8_t *src, int src_stride, int w, int h, } } -static uint16_t edge_probability(const uint8_t *input, int w, int h, +static EdgeInfo edge_probability(const uint8_t *input, int w, int h, bool high_bd, int bd) { // The probability of an edge in the whole image is the same as the highest // probability of an edge for any individual pixel. Use Sobel as the metric // for finding an edge. uint16_t highest = 0; + uint16_t highest_x = 0; + uint16_t highest_y = 0; // Ignore the 1 pixel border around the image for the computation. for (int j = 1; j < h - 1; ++j) { for (int i = 1; i < w - 1; ++i) { @@ -13072,18 +14104,22 @@ static uint16_t edge_probability(const uint8_t *input, int w, int h, int16_t g_y = g.y >> (bd - 8); uint16_t magnitude = (uint16_t)sqrt(g_x * g_x + g_y * g_y); highest = AOMMAX(highest, magnitude); + highest_x = AOMMAX(highest_x, g_x); + highest_y = AOMMAX(highest_y, g_y); } } - return highest; + EdgeInfo ei = { .magnitude = highest, .x = highest_x, .y = highest_y }; + return ei; } /* Uses most of the Canny edge detection algorithm to find if there are any * edges in the image. */ -uint16_t av1_edge_exists(const uint8_t *src, int src_stride, int w, int h, +EdgeInfo av1_edge_exists(const uint8_t *src, int src_stride, int w, int h, bool high_bd, int bd) { if (w < 3 || h < 3) { - return 0; + EdgeInfo n = { .magnitude = 0, .x = 0, .y = 0 }; + return n; } uint8_t *blurred; if (high_bd) { @@ -13096,7 +14132,7 @@ uint16_t av1_edge_exists(const uint8_t *src, int src_stride, int w, int h, // want a probability of an edge existing in the buffer, which is determined // by the strongest edge in it -- we don't need to eliminate the weaker // edges. Use Sobel for the edge detection. - uint16_t prob = edge_probability(blurred, w, h, high_bd, bd); + EdgeInfo prob = edge_probability(blurred, w, h, high_bd, bd); if (high_bd) { aom_free(CONVERT_TO_SHORTPTR(blurred)); } else { diff --git a/third_party/aom/av1/encoder/rdopt.h b/third_party/aom/av1/encoder/rdopt.h index 983d3850df..7ba1b18201 100644 --- a/third_party/aom/av1/encoder/rdopt.h +++ b/third_party/aom/av1/encoder/rdopt.h @@ -123,18 +123,33 @@ void av1_rd_pick_inter_mode_sb(struct AV1_COMP *cpi, struct RD_STATS *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far); +void av1_nonrd_pick_inter_mode_sb(struct AV1_COMP *cpi, + struct TileDataEnc *tile_data, + struct macroblock *x, int mi_row, int mi_col, + struct RD_STATS *rd_cost, BLOCK_SIZE bsize, + PICK_MODE_CONTEXT *ctx, + int64_t best_rd_so_far); + void av1_rd_pick_inter_mode_sb_seg_skip( const struct AV1_COMP *cpi, struct TileDataEnc *tile_data, struct macroblock *x, int mi_row, int mi_col, struct RD_STATS *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far); +// The best edge strength seen in the block, as well as the best x and y +// components of edge strength seen. +typedef struct { + uint16_t magnitude; + uint16_t x; + uint16_t y; +} EdgeInfo; + /** Returns an integer indicating the strength of the edge. * 0 means no edge found, 556 is the strength of a solid black/white edge, * and the number may range higher if the signal is even stronger (e.g., on a * corner). high_bd is a bool indicating the source should be treated * as a 16-bit array. bd is the bit depth. */ -uint16_t av1_edge_exists(const uint8_t *src, int src_stride, int w, int h, +EdgeInfo av1_edge_exists(const uint8_t *src, int src_stride, int w, int h, bool high_bd, int bd); /** Applies a Gaussian blur with sigma = 1.3. Used by av1_edge_exists and diff --git a/third_party/aom/av1/encoder/speed_features.c b/third_party/aom/av1/encoder/speed_features.c index bbb68426fa..5dfc585a29 100644 --- a/third_party/aom/av1/encoder/speed_features.c +++ b/third_party/aom/av1/encoder/speed_features.c @@ -17,12 +17,6 @@ #include "aom_dsp/aom_dsp_common.h" -// Setting this to 1 will disable trellis optimization completely. -// Setting this to 2 will disable trellis optimization within the -// transform search. Trellis optimization will still be applied -// in the final encode. -#define DISABLE_TRELLISQ_SEARCH 0 - #define MAX_MESH_SPEED 5 // Max speed setting for mesh motion method // Max speed setting for tx domain evaluation #define MAX_TX_DOMAIN_EVAL_SPEED 5 @@ -96,13 +90,6 @@ static BLOCK_SIZE set_partition_min_limit(const AV1_COMMON *const cm) { } } -// Do we have an internal image edge (e.g. formatting bars). -static int has_internal_image_edge(const AV1_COMP *cpi) { - return (cpi->oxcf.pass == 2) && - ((cpi->twopass.this_frame_stats.inactive_zone_rows > 0) || - (cpi->twopass.this_frame_stats.inactive_zone_cols > 0)); -} - static void set_good_speed_feature_framesize_dependent( const AV1_COMP *const cpi, SPEED_FEATURES *const sf, int speed) { const AV1_COMMON *const cm = &cpi->common; @@ -111,8 +98,13 @@ static void set_good_speed_feature_framesize_dependent( if (is_480p_or_larger) { sf->use_square_partition_only_threshold = BLOCK_128X128; + if (is_720p_or_larger) + sf->auto_max_partition_based_on_simple_motion = ADAPT_PRED; + else + sf->auto_max_partition_based_on_simple_motion = RELAXED_PRED; } else { sf->use_square_partition_only_threshold = BLOCK_64X64; + sf->auto_max_partition_based_on_simple_motion = DIRECT_PRED; } // TODO(huisu@google.com): train models for 720P and above. @@ -124,6 +116,11 @@ static void set_good_speed_feature_framesize_dependent( sf->ml_partition_search_breakout_thresh[4] = -1; // BLOCK_128X128 } + if (is_720p_or_larger && speed >= CONFIG_2PASS_PARTITION_SEARCH_LVL_START && + speed < CONFIG_2PASS_PARTITION_SEARCH_LVL_END) { + sf->two_pass_partition_search = 1; + } + if (speed >= 1) { if (is_720p_or_larger) { sf->use_square_partition_only_threshold = BLOCK_128X128; @@ -139,6 +136,8 @@ static void set_good_speed_feature_framesize_dependent( sf->ml_partition_search_breakout_thresh[2] = 300; // BLOCK_32X32 sf->ml_partition_search_breakout_thresh[3] = 300; // BLOCK_64X64 sf->ml_partition_search_breakout_thresh[4] = -1; // BLOCK_128X128 + + sf->firstpass_simple_motion_search_early_term = 1; } } @@ -155,13 +154,10 @@ static void set_good_speed_feature_framesize_dependent( } if (is_720p_or_larger) { - sf->disable_split_mask = - cm->show_frame ? DISABLE_ALL_SPLIT : DISABLE_ALL_INTER_SPLIT; sf->adaptive_pred_interp_filter = 0; sf->partition_search_breakout_dist_thr = (1 << 24); sf->partition_search_breakout_rate_thr = 120; } else { - sf->disable_split_mask = LAST_AND_INTRA_SPLIT_ONLY; sf->partition_search_breakout_dist_thr = (1 << 22); sf->partition_search_breakout_rate_thr = 100; } @@ -170,24 +166,15 @@ static void set_good_speed_feature_framesize_dependent( if (speed >= 3) { if (is_720p_or_larger) { - sf->disable_split_mask = DISABLE_ALL_SPLIT; sf->partition_search_breakout_dist_thr = (1 << 25); sf->partition_search_breakout_rate_thr = 200; } else { sf->max_intra_bsize = BLOCK_32X32; - sf->disable_split_mask = DISABLE_ALL_INTER_SPLIT; sf->partition_search_breakout_dist_thr = (1 << 23); sf->partition_search_breakout_rate_thr = 120; } - } - - // If this is a two pass clip that fits the criteria for animated or - // graphics content then reset disable_split_mask for speeds 2+. - // Also if the image edge is internal to the coded area. - if ((speed >= 2) && (cpi->oxcf.pass == 2) && - ((cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION) || - (has_internal_image_edge(cpi)))) { - sf->disable_split_mask = DISABLE_COMPOUND_SPLIT; + sf->use_first_partition_pass_interintra_stats = + sf->two_pass_partition_search; } if (speed >= 4) { @@ -196,7 +183,6 @@ static void set_good_speed_feature_framesize_dependent( } else { sf->partition_search_breakout_dist_thr = (1 << 24); } - sf->disable_split_mask = DISABLE_ALL_SPLIT; } } @@ -222,9 +208,11 @@ static void set_good_speed_features_framesize_independent( // TODO(debargha): Test, tweak and turn on either 1 or 2 sf->inter_mode_rd_model_estimation = 1; + sf->inter_mode_rd_model_estimation_adaptive = 0; - sf->prune_ref_frame_for_rect_partitions = !is_boosted_arf2_bwd_type; - sf->prune_ref_mode_for_partitions = sf->prune_ref_frame_for_rect_partitions; + sf->two_loop_comp_search = 0; + sf->prune_ref_frame_for_rect_partitions = + boosted ? 0 : (is_boosted_arf2_bwd_type ? 1 : 2); sf->less_rectangular_check_level = 1; sf->gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3; sf->gm_disable_recode = 1; @@ -237,19 +225,16 @@ static void set_good_speed_features_framesize_independent( sf->disable_wedge_search_edge_thresh = 0; sf->prune_motion_mode_level = 1; sf->cb_pred_filter_search = 0; + sf->use_nonrd_pick_mode = 0; + sf->use_real_time_ref_set = 0; if (speed >= 1) { sf->gm_erroradv_type = GM_ERRORADV_TR_1; sf->selective_ref_frame = 2; - sf->inter_tx_size_search_init_depth_rect = 1; - sf->inter_tx_size_search_init_depth_sqr = 1; sf->intra_tx_size_search_init_depth_rect = 1; sf->tx_size_search_lgr_block = 1; - if (speed >= CONFIG_2PASS_PARTITION_SEARCH_LVL) { - sf->two_pass_partition_search = 1; - sf->mode_pruning_based_on_two_pass_partition_search = 1; - } + sf->prune_ext_partition_types_search_level = 2; sf->skip_repeat_interpolation_filter_search = 1; sf->tx_type_search.skip_tx_search = 1; @@ -270,6 +255,7 @@ static void set_good_speed_features_framesize_independent( sf->prune_single_motion_modes_by_simple_trans = 1; sf->simple_motion_search_split_only = 1; + sf->simple_motion_search_early_term_none = 1; sf->disable_wedge_search_var_thresh = 0; sf->disable_wedge_search_edge_thresh = 0; @@ -280,12 +266,16 @@ static void set_good_speed_features_framesize_independent( sf->cb_pred_filter_search = 1; sf->use_transform_domain_distortion = boosted ? 0 : 1; sf->perform_coeff_opt = boosted ? 0 : 1; + sf->use_inter_txb_hash = 0; } if (speed >= 2) { sf->gm_erroradv_type = GM_ERRORADV_TR_2; sf->selective_ref_frame = 3; + sf->inter_tx_size_search_init_depth_rect = 1; + sf->inter_tx_size_search_init_depth_sqr = 1; + sf->fast_cdef_search = 1; sf->adaptive_rd_thresh = 1; @@ -295,9 +285,6 @@ static void set_good_speed_features_framesize_independent( sf->comp_inter_joint_search_thresh = BLOCK_SIZES_ALL; sf->partition_search_breakout_rate_thr = 80; - // Note: This speed feature is disable as it seems to be worse in - // compression/quality and is also slower. - // sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX; sf->allow_partition_search_skip = 1; sf->disable_wedge_search_var_thresh = 100; sf->disable_wedge_search_edge_thresh = 0; @@ -306,13 +293,13 @@ static void set_good_speed_features_framesize_independent( sf->disable_dual_filter = 1; sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_DISABLED; sf->prune_comp_type_by_comp_avg = 2; + // TODO(Sachin): Enable/Enhance this speed feature for speed 2 & 3 sf->cb_pred_filter_search = 0; sf->adaptive_interp_filter_search = 1; sf->perform_coeff_opt = boosted ? 0 : 2; } if (speed >= 3) { - sf->selective_ref_frame = 4; sf->tx_size_search_method = boosted ? USE_FULL_RD : USE_LARGESTALL; sf->less_rectangular_check_level = 2; sf->adaptive_pred_interp_filter = 1; @@ -324,6 +311,12 @@ static void set_good_speed_features_framesize_independent( sf->use_transform_domain_distortion = boosted ? 1 : 2; sf->use_accurate_subpel_search = USE_2_TAPS; sf->adaptive_rd_thresh = 2; + if (cpi->oxcf.enable_smooth_interintra) { + sf->disable_smooth_interintra = + (boosted || cpi->refresh_bwd_ref_frame || cpi->refresh_alt2_ref_frame) + ? 0 + : 1; + } sf->tx_type_search.prune_mode = PRUNE_2D_FAST; sf->gm_search_type = GM_DISABLE_SEARCH; sf->prune_comp_search_by_single_result = 2; @@ -332,18 +325,32 @@ static void set_good_speed_features_framesize_independent( // TODO(yunqing): evaluate this speed feature for speed 1 & 2, and combine // it with cpi->sf.disable_wedge_search_var_thresh. sf->disable_wedge_interintra_search = 1; + // TODO(any): Experiment with the early exit mechanism for speeds 0, 1 and 2 + // and clean-up the speed feature + sf->perform_best_rd_based_gating_for_chroma = 1; + sf->prune_ref_frame_for_rect_partitions = + frame_is_intra_only(&cpi->common) ? 0 : (boosted ? 1 : 2); sf->perform_coeff_opt = is_boosted_arf2_bwd_type ? 2 : 3; + sf->prune_comp_type_by_model_rd = boosted ? 0 : 1; + // TODO(Venkat): Clean-up frame type dependency for + // simple_motion_search_split_only in partition search function and set the + // speed feature accordingly + // TODO(Venkat): Evaluate this speed feature for speed 1 & 2 + sf->simple_motion_search_split_only = + cm->allow_screen_content_tools ? 1 : 2; + sf->disable_smooth_intra = + !frame_is_intra_only(&cpi->common) || (cpi->rc.frames_to_key != 1); } if (speed >= 4) { sf->use_intra_txb_hash = 0; sf->tx_type_search.fast_intra_tx_type_search = 1; - sf->use_square_partition_only_threshold = - boosted ? BLOCK_128X128 : BLOCK_4X4; + sf->disable_loop_restoration_chroma = + (boosted || cm->allow_screen_content_tools) ? 0 : 1; sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED; sf->adaptive_pred_interp_filter = 0; + sf->cb_pred_filter_search = 1; sf->adaptive_mode_search = 1; - sf->cb_partition_search = !boosted; sf->alt_ref_search_fp = 1; sf->skip_sharp_interp_filter_search = 1; sf->perform_coeff_opt = is_boosted_arf2_bwd_type ? 2 : 4; @@ -358,7 +365,6 @@ static void set_good_speed_features_framesize_independent( sf->intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC_H_V_CFL; sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V; sf->intra_uv_mode_mask[TX_16X16] = UV_INTRA_DC_H_V_CFL; - sf->use_square_partition_only_threshold = BLOCK_4X4; sf->tx_size_search_method = USE_LARGESTALL; sf->mv.search_method = BIGDIA; sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; @@ -403,7 +409,211 @@ static void set_good_speed_features_framesize_independent( if (speed >= 8) { sf->mv.search_method = FAST_DIAMOND; sf->mv.subpel_force_stop = HALF_PEL; - sf->lpf_pick = LPF_PICK_MINIMAL_LPF; + sf->lpf_pick = LPF_PICK_FROM_Q; + } +} + +// TODO(kyslov): now this is very similar to +// set_good_speed_features_framesize_independent +// except it sets non-rd flag on speed8. This function will likely +// be modified in the future with RT-specific speed features +static void set_rt_speed_features_framesize_independent(AV1_COMP *cpi, + SPEED_FEATURES *sf, + int speed) { + AV1_COMMON *const cm = &cpi->common; + const int boosted = frame_is_boosted(cpi); + + // Speed 0 for all speed features that give neutral coding performance change. + sf->reduce_inter_modes = 1; + sf->prune_ext_partition_types_search_level = 1; + sf->ml_prune_rect_partition = 1; + sf->ml_prune_ab_partition = 1; + sf->ml_prune_4_partition = 1; + sf->adaptive_txb_search_level = 1; + sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_SKIP_MV_SEARCH; + sf->model_based_prune_tx_search_level = 1; + sf->model_based_post_interp_filter_breakout = 1; + sf->model_based_motion_mode_rd_breakout = 1; + + // TODO(debargha): Test, tweak and turn on either 1 or 2 + sf->inter_mode_rd_model_estimation = 0; + sf->inter_mode_rd_model_estimation_adaptive = 0; + sf->two_loop_comp_search = 0; + + sf->prune_ref_frame_for_rect_partitions = !boosted; + sf->less_rectangular_check_level = 1; + sf->gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3; + sf->gm_disable_recode = 1; + sf->use_fast_interpolation_filter_search = 1; + sf->intra_tx_size_search_init_depth_sqr = 1; + sf->intra_angle_estimation = 1; + sf->selective_ref_frame = 1; + sf->prune_wedge_pred_diff_based = 1; + sf->disable_wedge_search_var_thresh = 0; + sf->disable_wedge_search_edge_thresh = 0; + sf->prune_motion_mode_level = 1; + sf->cb_pred_filter_search = 0; + sf->use_nonrd_pick_mode = 0; + sf->use_real_time_ref_set = 0; + + if (speed >= 1) { + sf->gm_erroradv_type = GM_ERRORADV_TR_1; + sf->selective_ref_frame = 2; + + sf->intra_tx_size_search_init_depth_rect = 1; + sf->tx_size_search_lgr_block = 1; + sf->prune_ext_partition_types_search_level = 2; + sf->skip_repeat_interpolation_filter_search = 1; + sf->tx_type_search.skip_tx_search = 1; + sf->tx_type_search.ml_tx_split_thresh = 40; + sf->model_based_prune_tx_search_level = 0; + sf->adaptive_txb_search_level = 2; + sf->use_intra_txb_hash = 1; + sf->optimize_b_precheck = 1; + sf->dual_sgr_penalty_level = 1; + sf->use_accurate_subpel_search = USE_4_TAPS; + sf->reuse_inter_intra_mode = 1; + sf->prune_comp_search_by_single_result = 1; + sf->skip_repeated_newmv = 1; + sf->obmc_full_pixel_search_level = 1; + // TODO(anyone): Following speed feature will be further explored to + // identify the appropriate tradeoff between encoder performance and its + // speed. + sf->prune_single_motion_modes_by_simple_trans = 1; + + sf->simple_motion_search_prune_rect = 1; + + sf->disable_wedge_search_var_thresh = 0; + sf->disable_wedge_search_edge_thresh = 0; + sf->prune_comp_type_by_comp_avg = 1; + sf->prune_motion_mode_level = 2; + sf->gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2; + sf->cb_pred_filter_search = 1; + sf->use_transform_domain_distortion = boosted ? 0 : 1; + } + + if (speed >= 2) { + sf->gm_erroradv_type = GM_ERRORADV_TR_2; + + sf->selective_ref_frame = 3; + sf->inter_tx_size_search_init_depth_rect = 1; + sf->inter_tx_size_search_init_depth_sqr = 1; + sf->fast_cdef_search = 1; + + sf->adaptive_rd_thresh = 1; + sf->mv.auto_mv_step_size = 1; + sf->mv.subpel_iters_per_step = 1; + sf->disable_filter_search_var_thresh = 100; + sf->comp_inter_joint_search_thresh = BLOCK_SIZES_ALL; + + sf->partition_search_breakout_rate_thr = 80; + sf->allow_partition_search_skip = 1; + sf->disable_wedge_search_var_thresh = 100; + sf->disable_wedge_search_edge_thresh = 0; + sf->fast_wedge_sign_estimate = 1; + sf->disable_dual_filter = 1; + sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_DISABLED; + sf->prune_comp_type_by_comp_avg = 2; + sf->cb_pred_filter_search = 0; + sf->adaptive_interp_filter_search = 1; + } + + if (speed >= 3) { + sf->selective_ref_frame = 4; + sf->tx_size_search_method = boosted ? USE_FULL_RD : USE_LARGESTALL; + sf->less_rectangular_check_level = 2; + sf->adaptive_pred_interp_filter = 1; + // adaptive_motion_search breaks encoder multi-thread tests. + // The values in x->pred_mv[] differ for single and multi-thread cases. + // See aomedia:1778. + // sf->adaptive_motion_search = 1; + sf->recode_loop = ALLOW_RECODE_KFARFGF; + sf->use_transform_domain_distortion = 1; + sf->use_accurate_subpel_search = USE_2_TAPS; + sf->adaptive_rd_thresh = 2; + sf->tx_type_search.prune_mode = PRUNE_2D_FAST; + sf->gm_search_type = GM_DISABLE_SEARCH; + sf->prune_comp_search_by_single_result = 2; + sf->prune_motion_mode_level = boosted ? 2 : 3; + sf->prune_warp_using_wmtype = 1; + // TODO(yunqing): evaluate this speed feature for speed 1 & 2, and combine + // it with cpi->sf.disable_wedge_search_var_thresh. + sf->disable_wedge_interintra_search = 1; + } + + if (speed >= 4) { + sf->use_intra_txb_hash = 0; + sf->use_mb_rd_hash = 0; + sf->tx_type_search.fast_intra_tx_type_search = 1; + sf->tx_type_search.fast_inter_tx_type_search = 1; + sf->tx_size_search_method = + frame_is_intra_only(cm) ? USE_FULL_RD : USE_LARGESTALL; + sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED; + sf->adaptive_pred_interp_filter = 0; + sf->adaptive_mode_search = 1; + sf->alt_ref_search_fp = 1; + sf->skip_sharp_interp_filter_search = 1; + } + + if (speed >= 5) { + sf->recode_loop = ALLOW_RECODE_KFMAXBW; + sf->intra_y_mode_mask[TX_64X64] = INTRA_DC_H_V; + sf->intra_uv_mode_mask[TX_64X64] = UV_INTRA_DC_H_V_CFL; + sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V; + sf->intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC_H_V_CFL; + sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V; + sf->intra_uv_mode_mask[TX_16X16] = UV_INTRA_DC_H_V_CFL; + sf->tx_size_search_method = USE_LARGESTALL; + sf->mv.search_method = BIGDIA; + sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; + sf->adaptive_rd_thresh = 4; + sf->mode_search_skip_flags = + (cm->current_frame.frame_type == KEY_FRAME) + ? 0 + : FLAG_SKIP_INTRA_DIRMISMATCH | FLAG_SKIP_INTRA_BESTINTER | + FLAG_SKIP_COMP_BESTINTRA | FLAG_SKIP_INTRA_LOWVAR | + FLAG_EARLY_TERMINATE; + sf->disable_filter_search_var_thresh = 200; + sf->use_fast_coef_costing = 1; + sf->partition_search_breakout_rate_thr = 300; + sf->use_transform_domain_distortion = 2; + } + + if (speed >= 6) { + int i; + sf->optimize_coefficients = NO_TRELLIS_OPT; + sf->mv.search_method = HEX; + sf->disable_filter_search_var_thresh = 500; + for (i = 0; i < TX_SIZES; ++i) { + sf->intra_y_mode_mask[i] = INTRA_DC; + sf->intra_uv_mode_mask[i] = UV_INTRA_DC_CFL; + } + sf->partition_search_breakout_rate_thr = 500; + sf->mv.reduce_first_step_size = 1; + sf->simple_model_rd_from_var = 1; + } + if (speed >= 7) { + sf->default_max_partition_size = BLOCK_32X32; + sf->default_min_partition_size = BLOCK_8X8; + sf->intra_y_mode_mask[TX_64X64] = INTRA_DC; + sf->intra_y_mode_mask[TX_32X32] = INTRA_DC; + sf->frame_parameter_update = 0; + sf->mv.search_method = FAST_HEX; + sf->partition_search_type = REFERENCE_PARTITION; + sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH; + } + if (speed >= 8) { + sf->mv.search_method = FAST_DIAMOND; + sf->lpf_pick = LPF_PICK_FROM_Q; + sf->default_max_partition_size = BLOCK_128X128; + sf->default_min_partition_size = BLOCK_8X8; + sf->partition_search_type = VAR_BASED_PARTITION; + sf->use_real_time_ref_set = 1; + // Can't use LARGEST TX mode with pre-calculated partition + // and disabled TX64 + if (!cpi->oxcf.enable_tx64) sf->tx_size_search_method = USE_FAST_RD; + sf->use_nonrd_pick_mode = 1; + sf->inter_mode_rd_model_estimation = 2; } } @@ -415,10 +625,6 @@ void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi, int speed) { set_good_speed_feature_framesize_dependent(cpi, sf, speed); } - if (sf->disable_split_mask == DISABLE_ALL_SPLIT) { - sf->adaptive_pred_interp_filter = 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; @@ -440,24 +646,32 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { sf->mv.subpel_search_method = SUBPEL_TREE; sf->mv.subpel_iters_per_step = 2; sf->mv.subpel_force_stop = EIGHTH_PEL; -#if DISABLE_TRELLISQ_SEARCH == 2 - sf->optimize_coefficients = !is_lossless_requested(&cpi->oxcf) - ? FINAL_PASS_TRELLIS_OPT - : NO_TRELLIS_OPT; -#elif DISABLE_TRELLISQ_SEARCH == 1 - sf->optimize_coefficients = NO_TRELLIS_OPT; -#else - if (is_lossless_requested(&cpi->oxcf)) + if (cpi->oxcf.disable_trellis_quant == 3) { + sf->optimize_coefficients = !is_lossless_requested(&cpi->oxcf) + ? NO_ESTIMATE_YRD_TRELLIS_OPT + : NO_TRELLIS_OPT; + } else if (cpi->oxcf.disable_trellis_quant == 2) { + sf->optimize_coefficients = !is_lossless_requested(&cpi->oxcf) + ? FINAL_PASS_TRELLIS_OPT + : NO_TRELLIS_OPT; + } else if (cpi->oxcf.disable_trellis_quant == 0) { + if (is_lossless_requested(&cpi->oxcf)) + sf->optimize_coefficients = NO_TRELLIS_OPT; + else + sf->optimize_coefficients = FULL_TRELLIS_OPT; + } else if (cpi->oxcf.disable_trellis_quant == 1) { sf->optimize_coefficients = NO_TRELLIS_OPT; - else - sf->optimize_coefficients = FULL_TRELLIS_OPT; -#endif // DISABLE_TRELLISQ_SEARCH + } else { + assert(0 && "Invalid disable_trellis_quant value"); + } sf->gm_erroradv_type = GM_ERRORADV_TR_0; sf->mv.reduce_first_step_size = 0; sf->mv.auto_mv_step_size = 0; sf->comp_inter_joint_search_thresh = BLOCK_4X4; sf->adaptive_rd_thresh = 0; - sf->tx_size_search_method = USE_FULL_RD; + // TODO(sarahparker) Pair this with a speed setting once experiments are done + sf->trellis_eob_fast = 0; + sf->tx_size_search_method = cpi->oxcf.tx_size_search_method; sf->inter_tx_size_search_init_depth_sqr = 0; sf->inter_tx_size_search_init_depth_rect = 0; sf->intra_tx_size_search_init_depth_rect = 0; @@ -471,7 +685,6 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { sf->adaptive_motion_search = 0; sf->adaptive_pred_interp_filter = 0; sf->adaptive_mode_search = 0; - sf->cb_partition_search = 0; sf->alt_ref_search_fp = 0; sf->partition_search_type = SEARCH_PARTITION; sf->tx_type_search.prune_mode = PRUNE_2D_ACCURATE; @@ -484,19 +697,20 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { sf->less_rectangular_check_level = 0; sf->use_square_partition_only_threshold = BLOCK_128X128; sf->prune_ref_frame_for_rect_partitions = 0; - sf->prune_ref_mode_for_partitions = 0; - sf->auto_min_max_partition_size = NOT_IN_USE; + sf->auto_max_partition_based_on_simple_motion = NOT_IN_USE; + sf->auto_min_partition_based_on_simple_motion = 0; sf->rd_auto_partition_min_limit = BLOCK_4X4; sf->default_max_partition_size = BLOCK_LARGEST; sf->default_min_partition_size = BLOCK_4X4; sf->adjust_partitioning_from_last_frame = 0; - sf->disable_split_mask = 0; sf->mode_search_skip_flags = 0; sf->disable_filter_search_var_thresh = 0; sf->allow_partition_search_skip = 0; sf->use_accurate_subpel_search = USE_8_TAPS; sf->disable_wedge_search_edge_thresh = 0; + sf->use_first_partition_pass_interintra_stats = 0; sf->disable_wedge_search_var_thresh = 0; + sf->disable_loop_restoration_chroma = 0; sf->fast_wedge_sign_estimate = 0; sf->prune_wedge_pred_diff_based = 0; sf->drop_ref = 0; @@ -504,13 +718,13 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { sf->txb_split_cap = 1; sf->adaptive_txb_search_level = 0; sf->two_pass_partition_search = 0; - sf->mode_pruning_based_on_two_pass_partition_search = 0; + sf->firstpass_simple_motion_search_early_term = 0; sf->use_intra_txb_hash = 0; - // TODO(any) : clean use_inter_txb_hash code - sf->use_inter_txb_hash = 0; + sf->use_inter_txb_hash = 1; sf->use_mb_rd_hash = 1; sf->optimize_b_precheck = 0; - sf->dist_wtd_comp_fast_tx_search = 0; + sf->two_loop_comp_search = 1; + sf->second_loop_comp_fast_tx_search = 0; sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_ENABLED; sf->reuse_inter_intra_mode = 0; sf->intra_angle_estimation = 0; @@ -543,6 +757,7 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { } sf->simple_motion_search_split_only = 0; sf->simple_motion_search_prune_rect = 0; + sf->simple_motion_search_early_term_none = 0; // Set this at the appropriate speed levels sf->use_transform_domain_distortion = 0; @@ -563,19 +778,25 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { // inter_mode_rd_model_estimation in conjunction with // model_based_motion_mode_rd_breakout sf->inter_mode_rd_model_estimation = 0; + sf->inter_mode_rd_model_estimation_adaptive = 0; sf->obmc_full_pixel_search_level = 0; sf->skip_sharp_interp_filter_search = 0; sf->prune_comp_type_by_comp_avg = 0; sf->disable_interinter_wedge_newmv_search = 0; + sf->disable_smooth_interintra = 0; sf->prune_motion_mode_level = 0; sf->prune_warp_using_wmtype = 0; - sf->disable_wedge_interintra_search = 0; sf->perform_coeff_opt = 0; + sf->prune_comp_type_by_model_rd = 0; + sf->disable_smooth_intra = 0; + sf->perform_best_rd_based_gating_for_chroma = 0; if (oxcf->mode == GOOD) set_good_speed_features_framesize_independent(cpi, sf, speed); + else if (oxcf->mode == REALTIME) + set_rt_speed_features_framesize_independent(cpi, sf, speed); if (!cpi->seq_params_locked) { cpi->common.seq_params.enable_dual_filter &= !sf->disable_dual_filter; @@ -621,11 +842,13 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { // so make sure they are always turned off. if (oxcf->pass == 1) sf->optimize_coefficients = NO_TRELLIS_OPT; - // No recode for 1 pass. + // No recode or trellis for 1 pass. if (oxcf->pass == 0) { sf->recode_loop = DISALLOW_RECODE; sf->optimize_coefficients = NO_TRELLIS_OPT; } + // FIXME: trellis not very efficient for quantization matrices + if (oxcf->using_qm) sf->optimize_coefficients = NO_TRELLIS_OPT; if (sf->mv.subpel_search_method == SUBPEL_TREE) { cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree; @@ -637,12 +860,6 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned_evenmore; } - cpi->optimize_speed_feature = - oxcf->pass != 1 ? sf->optimize_coefficients : NO_TRELLIS_OPT; - // FIXME: trellis not very efficient for quantisation matrices - if (oxcf->using_qm) cpi->optimize_speed_feature = NO_TRELLIS_OPT; - if (oxcf->disable_trellis_quant) cpi->optimize_speed_feature = NO_TRELLIS_OPT; - x->min_partition_size = sf->default_min_partition_size; x->max_partition_size = sf->default_max_partition_size; @@ -670,7 +887,9 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { #endif // CONFIG_DIST_8X8 if (cpi->oxcf.row_mt == 1 && (cpi->oxcf.max_threads > 1)) { sf->adaptive_rd_thresh = 0; - if (sf->inter_mode_rd_model_estimation == 1) + if (sf->inter_mode_rd_model_estimation == 1) { sf->inter_mode_rd_model_estimation = 0; + sf->inter_mode_rd_model_estimation_adaptive = 0; + } } } diff --git a/third_party/aom/av1/encoder/speed_features.h b/third_party/aom/av1/encoder/speed_features.h index 2216c7be04..a3211922b7 100644 --- a/third_party/aom/av1/encoder/speed_features.h +++ b/third_party/aom/av1/encoder/speed_features.h @@ -119,11 +119,6 @@ enum { USE_LARGESTALL, } UENUM1BYTE(TX_SIZE_SEARCH_METHOD); -enum { - NOT_IN_USE = 0, - RELAXED_NEIGHBORING_MIN_MAX = 1 -} UENUM1BYTE(AUTO_MIN_MAX_MODE); - enum { // Try the full image with different values. LPF_PICK_FROM_FULL_IMAGE, @@ -191,7 +186,9 @@ enum { // Always use a fixed size partition FIXED_PARTITION, - REFERENCE_PARTITION + REFERENCE_PARTITION, + + VAR_BASED_PARTITION } UENUM1BYTE(PARTITION_SEARCH_TYPE); enum { @@ -201,6 +198,13 @@ enum { FULL_PEL } UENUM1BYTE(SUBPEL_FORCE_STOP); +enum { + NOT_IN_USE, + DIRECT_PRED, + RELAXED_PRED, + ADAPT_PRED +} UENUM1BYTE(MAX_PART_PRED_MODE); + typedef struct MV_SPEED_FEATURES { // Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc). SEARCH_METHODS search_method; @@ -248,9 +252,10 @@ enum { } UENUM1BYTE(GM_ERRORADV_TYPE); enum { - NO_TRELLIS_OPT, // No trellis optimization - FULL_TRELLIS_OPT, // Trellis optimization in all stages - FINAL_PASS_TRELLIS_OPT // Trellis optimization in only the final encode pass + NO_TRELLIS_OPT, // No trellis optimization + FULL_TRELLIS_OPT, // Trellis optimization in all stages + FINAL_PASS_TRELLIS_OPT, // Trellis optimization in only the final encode pass + NO_ESTIMATE_YRD_TRELLIS_OPT // Disable trellis in estimate_yrd_for_sb } UENUM1BYTE(TRELLIS_OPT_TYPE); enum { @@ -370,6 +375,10 @@ typedef struct SPEED_FEATURES { // Use a ML model to prune horz and vert partitions int ml_prune_rect_partition; + // Disable/Enable interintra motion mode based on stats collected during + // first_partition_search_pass + int use_first_partition_pass_interintra_stats; + // Use a ML model to prune horz_a, horz_b, vert_a and vert_b partitions. int ml_prune_ab_partition; @@ -378,12 +387,13 @@ typedef struct SPEED_FEATURES { int fast_cdef_search; - // 2-pass coding block partition search + // 2-pass coding block partition search, and also use the mode decisions made + // in the initial partition search to prune mode candidates, e.g. ref frames. int two_pass_partition_search; - // Use the mode decisions made in the initial partition search to prune mode - // candidates, e.g. ref frames. - int mode_pruning_based_on_two_pass_partition_search; + // Terminate early in firstpass of two_pass partition search for faster + // firstpass. + int firstpass_simple_motion_search_early_term; // Skip rectangular partition test when partition type none gives better // rd than partition type split. Can take values 0 - 2, 0 referring to no @@ -394,14 +404,17 @@ typedef struct SPEED_FEATURES { BLOCK_SIZE use_square_partition_only_threshold; // Prune reference frames for rectangular partitions. + // 0 implies no pruning + // 1 implies prune for extended partition + // 2 implies prune horiz, vert and extended partition int prune_ref_frame_for_rect_partitions; - // Prune ref/mode choices for partitions. - int prune_ref_mode_for_partitions; + // Sets min and max square partition levels for this superblock based on + // motion vector and prediction error distribution produced from 16x16 + // simple motion search + MAX_PART_PRED_MODE auto_max_partition_based_on_simple_motion; + int auto_min_partition_based_on_simple_motion; - // Sets min and max partition sizes for this superblock based on the - // same superblock in last encoded frame, and the left and above neighbor. - AUTO_MIN_MAX_MODE auto_min_max_partition_size; // Ensures the rd based auto partition search will always // go down at least to the specified level. BLOCK_SIZE rd_auto_partition_min_limit; @@ -415,11 +428,6 @@ typedef struct SPEED_FEATURES { // frame's partitioning. Only used if use_lastframe_partitioning is set. int adjust_partitioning_from_last_frame; - // Disables sub 8x8 blocksizes in different scenarios: Choices are to disable - // it always, to allow it for only Last frame and Intra, disable it for all - // inter modes or to enable it always. - int disable_split_mask; - // TODO(jingning): combine the related motion search speed features // This allows us to use motion search at other sizes as a starting // point for this motion search and limits the search range around it. @@ -446,8 +454,6 @@ typedef struct SPEED_FEATURES { // Adaptive prediction mode search int adaptive_mode_search; - int cb_partition_search; - int alt_ref_search_fp; // Implements various heuristics to skip searching modes @@ -560,8 +566,11 @@ typedef struct SPEED_FEATURES { // Calculate RD cost before doing optimize_b, and skip if the cost is large. int optimize_b_precheck; - // Use model rd instead of transform search in dist_wtd_comp - int dist_wtd_comp_fast_tx_search; + // Use two-loop compound search + int two_loop_comp_search; + + // Use model rd instead of transform search in second loop of compound search + int second_loop_comp_fast_tx_search; // Decide when and how to use joint_comp. DIST_WTD_COMP_FLAG use_dist_wtd_comp_flag; @@ -573,7 +582,7 @@ typedef struct SPEED_FEATURES { // 2-pass inter mode model estimation where the preliminary pass skips // transform search and uses a model to estimate rd, while the final pass - // computes the full transform search. two types of models are supported: + // computes the full transform search. Two types of models are supported: // 0: not used // 1: used with online dynamic rd model // 2: used with static rd model @@ -613,6 +622,9 @@ typedef struct SPEED_FEATURES { // Enable/disable ME for interinter wedge search. int disable_interinter_wedge_newmv_search; + // Enable/disable smooth inter-intra mode + int disable_smooth_interintra; + // skip sharp_filter evaluation based on regular and smooth filter rd for // dual_filter=0 case int skip_sharp_interp_filter_search; @@ -639,6 +651,10 @@ typedef struct SPEED_FEATURES { // want to split directly without trying other partition types. int simple_motion_search_split_only; + // Use features from simple_motion_search to terminate prediction block + // partition after PARTITION_NONE + int simple_motion_search_early_term_none; + int cb_pred_filter_search; // adaptive interp_filter search to allow skip of certain filter types. @@ -647,11 +663,38 @@ typedef struct SPEED_FEATURES { // mask for skip evaluation of certain interp_filter type. INTERP_FILTER_MASK interp_filter_search_mask; + // Flag used to control the ref_best_rd based gating for chroma + int perform_best_rd_based_gating_for_chroma; + // Enable/disable interintra wedge search. int disable_wedge_interintra_search; + // Disable loop restoration for Chroma plane + int disable_loop_restoration_chroma; + // Flag used to control the extent of coeff R-D optimization int perform_coeff_opt; + + // Flag used to control the speed of the eob selection in trellis. + int trellis_eob_fast; + + // This flag controls the use of non-RD mode decision. + int use_nonrd_pick_mode; + + // prune wedge and compound segment approximate rd evaluation based on + // compound average modeled rd + int prune_comp_type_by_model_rd; + + // Enable/disable smooth intra modes. + int disable_smooth_intra; + + // use reduced ref set for real-time mode + int use_real_time_ref_set; + + // Perform a full TX search on some modes while using the + // inter-mode RD model for others. Only enabled when + // inter_mode_rd_model_estimation != 0 + int inter_mode_rd_model_estimation_adaptive; } SPEED_FEATURES; struct AV1_COMP; diff --git a/third_party/aom/av1/encoder/temporal_filter.c b/third_party/aom/av1/encoder/temporal_filter.c index 385f027932..ba883d7881 100644 --- a/third_party/aom/av1/encoder/temporal_filter.c +++ b/third_party/aom/av1/encoder/temporal_filter.c @@ -37,6 +37,16 @@ #define EDGE_THRESHOLD 50 #define SQRT_PI_BY_2 1.25331413732 +static unsigned int index_mult[14] = { + 0, 0, 0, 0, 49152, 39322, 32768, 28087, 24576, 21846, 19661, 17874, 0, 15124 +}; + +static int64_t highbd_index_mult[14] = { 0U, 0U, 0U, + 0U, 3221225472U, 2576980378U, + 2147483648U, 1840700270U, 1610612736U, + 1431655766U, 1288490189U, 1171354718U, + 0U, 991146300U }; + static void temporal_filter_predictors_mb_c( MACROBLOCKD *xd, uint8_t *y_mb_ptr, uint8_t *u_mb_ptr, uint8_t *v_mb_ptr, int stride, int uv_block_width, int uv_block_height, int mv_row, int mv_col, @@ -61,7 +71,9 @@ static void temporal_filter_predictors_mb_c( } if (use_32x32) { - const MV mv = { mv_row, mv_col }; + assert(mv_row >= INT16_MIN && mv_row <= INT16_MAX && mv_col >= INT16_MIN && + mv_col <= INT16_MAX); + const MV mv = { (int16_t)mv_row, (int16_t)mv_col }; av1_build_inter_predictor(y_mb_ptr, stride, &pred[0], BW, &mv, scale, BW, BH, &conv_params, interp_filters, &warp_types, x, @@ -165,12 +177,38 @@ static void highbd_apply_temporal_filter_self( } } -static INLINE int mod_index(int64_t sum_dist, int index, int rounding, - int strength, int filter_weight) { - int mod = (int)(((sum_dist * 3) / index + rounding) >> strength); +static INLINE int mod_index(int sum_dist, int index, int rounding, int strength, + int filter_weight) { + assert(index >= 0 && index <= 13); + assert(index_mult[index] != 0); + + int mod = (clamp(sum_dist, 0, UINT16_MAX) * index_mult[index]) >> 16; + mod += rounding; + mod >>= strength; + mod = AOMMIN(16, mod); + mod = 16 - mod; mod *= filter_weight; + + return mod; +} + +static INLINE int highbd_mod_index(int64_t sum_dist, int index, int rounding, + int strength, int filter_weight) { + assert(index >= 0 && index <= 13); + assert(highbd_index_mult[index] != 0); + + int mod = + (int)((AOMMIN(sum_dist, INT32_MAX) * highbd_index_mult[index]) >> 32); + mod += rounding; + mod >>= strength; + + mod = AOMMIN(16, mod); + + mod = 16 - mod; + mod *= filter_weight; + return mod; } @@ -192,7 +230,7 @@ static INLINE void calculate_squared_errors(const uint8_t *s, int s_stride, static INLINE int get_filter_weight(unsigned int i, unsigned int j, unsigned int block_height, - unsigned int block_width, int *blk_fw, + unsigned int block_width, const int *blk_fw, int use_32x32) { if (use_32x32) // blk_fw[0] ~ blk_fw[3] are the same. @@ -213,12 +251,12 @@ static INLINE int get_filter_weight(unsigned int i, unsigned int j, return filter_weight; } -static void apply_temporal_filter( +void av1_apply_temporal_filter_c( const uint8_t *y_frame1, int y_stride, const uint8_t *y_pred, int y_buf_stride, const uint8_t *u_frame1, const uint8_t *v_frame1, int uv_stride, const uint8_t *u_pred, const uint8_t *v_pred, int uv_buf_stride, unsigned int block_width, unsigned int block_height, - int ss_x, int ss_y, int strength, int *blk_fw, int use_32x32, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count) { unsigned int i, j, k, m; @@ -355,14 +393,14 @@ static INLINE void highbd_calculate_squared_errors( } } -static void highbd_apply_temporal_filter( +void av1_highbd_apply_temporal_filter_c( const uint8_t *yf, int y_stride, const uint8_t *yp, int y_buf_stride, const uint8_t *uf, const uint8_t *vf, int uv_stride, const uint8_t *up, const uint8_t *vp, int uv_buf_stride, unsigned int block_width, - unsigned int block_height, int ss_x, int ss_y, int strength, int *blk_fw, - int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, - uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, - uint16_t *v_count) { + unsigned int block_height, int ss_x, int ss_y, int strength, + const int *blk_fw, int use_32x32, uint32_t *y_accumulator, + uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, + uint32_t *v_accumulator, uint16_t *v_count) { unsigned int i, j, k, m; int64_t modifier; const int rounding = (1 << strength) >> 1; @@ -426,8 +464,8 @@ static void highbd_apply_temporal_filter( y_index += 2; - const int final_y_mod = - mod_index(modifier, y_index, rounding, strength, filter_weight); + const int final_y_mod = highbd_mod_index(modifier, y_index, rounding, + strength, filter_weight); y_count[k] += final_y_mod; y_accumulator[k] += final_y_mod * pixel_value; @@ -472,10 +510,10 @@ static void highbd_apply_temporal_filter( u_mod += y_diff; v_mod += y_diff; - const int final_u_mod = - mod_index(u_mod, cr_index, rounding, strength, filter_weight); - const int final_v_mod = - mod_index(v_mod, cr_index, rounding, strength, filter_weight); + const int final_u_mod = highbd_mod_index(u_mod, cr_index, rounding, + strength, filter_weight); + const int final_v_mod = highbd_mod_index(v_mod, cr_index, rounding, + strength, filter_weight); u_count[m] += final_u_mod; u_accumulator[m] += final_u_mod * u_pixel_value; @@ -492,7 +530,7 @@ static void highbd_apply_temporal_filter( void av1_temporal_filter_apply_c(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, - int *blk_fw, int use_32x32, + const int *blk_fw, int use_32x32, unsigned int *accumulator, uint16_t *count) { unsigned int i, j, k; int modifier; @@ -659,7 +697,7 @@ static int temporal_filter_find_matching_mb_c(AV1_COMP *cpi, // x->best_mv. av1_full_pixel_search(cpi, x, TF_BLOCK, &best_ref_mv1_full, step_param, NSTEP, 1, sadpb, cond_cost_list(cpi, cost_list), &best_ref_mv1, - 0, 0, x_pos, y_pos, 0); + 0, 0, x_pos, y_pos, 0, &cpi->ss_cfg[SS_CFG_LOOKAHEAD]); x->mv_limits = tmp_mv_limits; // Ignore mv costing by sending NULL pointer instead of cost array @@ -713,9 +751,10 @@ static int temporal_filter_find_matching_mb_c(AV1_COMP *cpi, xd->plane[0].pre[0].stride = stride; av1_set_mv_search_range(&x->mv_limits, &best_ref_mv1); - av1_full_pixel_search( - cpi, x, TF_SUB_BLOCK, &best_ref_mv1_full, step_param, NSTEP, 1, sadpb, - cond_cost_list(cpi, cost_list), &best_ref_mv1, 0, 0, x_pos, y_pos, 0); + av1_full_pixel_search(cpi, x, TF_SUB_BLOCK, &best_ref_mv1_full, + step_param, NSTEP, 1, sadpb, + cond_cost_list(cpi, cost_list), &best_ref_mv1, 0, 0, + x_pos, y_pos, 0, &cpi->ss_cfg[SS_CFG_LOOKAHEAD]); x->mv_limits = tmp_mv_limits; blk_bestsme[k] = cpi->find_fractional_mv_step( @@ -750,7 +789,9 @@ static void temporal_filter_iterate_c(AV1_COMP *cpi, int mb_cols = (frames[alt_ref_index]->y_crop_width + BW - 1) >> BW_LOG2; int mb_rows = (frames[alt_ref_index]->y_crop_height + BH - 1) >> BH_LOG2; int mb_y_offset = 0; + int mb_y_src_offset = 0; int mb_uv_offset = 0; + int mb_uv_src_offset = 0; DECLARE_ALIGNED(16, unsigned int, accumulator[BLK_PELS * 3]); DECLARE_ALIGNED(16, uint16_t, count[BLK_PELS * 3]); MACROBLOCKD *mbd = &cpi->td.mb.e_mbd; @@ -833,9 +874,10 @@ static void temporal_filter_iterate_c(AV1_COMP *cpi, // Find best match in this frame by MC int err = temporal_filter_find_matching_mb_c( - cpi, frames[alt_ref_index]->y_buffer + mb_y_offset, - frames[frame]->y_buffer + mb_y_offset, frames[frame]->y_stride, - mb_col * BW, mb_row * BH, blk_mvs, blk_bestsme); + cpi, frames[alt_ref_index]->y_buffer + mb_y_src_offset, + frames[frame]->y_buffer + mb_y_src_offset, + frames[frame]->y_stride, mb_col * BW, mb_row * BH, blk_mvs, + blk_bestsme); int err16 = blk_bestsme[0] + blk_bestsme[1] + blk_bestsme[2] + blk_bestsme[3]; @@ -867,13 +909,13 @@ static void temporal_filter_iterate_c(AV1_COMP *cpi, if (blk_fw[0] || blk_fw[1] || blk_fw[2] || blk_fw[3]) { // Construct the predictors temporal_filter_predictors_mb_c( - mbd, frames[frame]->y_buffer + mb_y_offset, - frames[frame]->u_buffer + mb_uv_offset, - frames[frame]->v_buffer + mb_uv_offset, frames[frame]->y_stride, - mb_uv_width, mb_uv_height, mbd->mi[0]->mv[0].as_mv.row, - mbd->mi[0]->mv[0].as_mv.col, predictor, ref_scale_factors, - mb_col * BW, mb_row * BH, cm->allow_warped_motion, num_planes, - blk_mvs, use_32x32); + mbd, frames[frame]->y_buffer + mb_y_src_offset, + frames[frame]->u_buffer + mb_uv_src_offset, + frames[frame]->v_buffer + mb_uv_src_offset, + frames[frame]->y_stride, mb_uv_width, mb_uv_height, + mbd->mi[0]->mv[0].as_mv.row, mbd->mi[0]->mv[0].as_mv.col, + predictor, ref_scale_factors, mb_col * BW, mb_row * BH, + cm->allow_warped_motion, num_planes, blk_mvs, use_32x32); // Apply the filter (YUV) if (frame == alt_ref_index) { @@ -907,37 +949,39 @@ static void temporal_filter_iterate_c(AV1_COMP *cpi, if (num_planes <= 1) { // Single plane case av1_highbd_temporal_filter_apply_c( - f->y_buffer + mb_y_offset, f->y_stride, predictor, BW, BH, - adj_strength, blk_fw, use_32x32, accumulator, count); + f->y_buffer + mb_y_src_offset, f->y_stride, predictor, BW, + BH, adj_strength, blk_fw, use_32x32, accumulator, count); } else { // Process 3 planes together. - highbd_apply_temporal_filter( - f->y_buffer + mb_y_offset, f->y_stride, predictor, BW, - f->u_buffer + mb_uv_offset, f->v_buffer + mb_uv_offset, - f->uv_stride, predictor + BLK_PELS, - predictor + (BLK_PELS << 1), mb_uv_width, BW, BH, - mbd->plane[1].subsampling_x, mbd->plane[1].subsampling_y, - adj_strength, blk_fw, use_32x32, accumulator, count, - accumulator + BLK_PELS, count + BLK_PELS, - accumulator + (BLK_PELS << 1), count + (BLK_PELS << 1)); + av1_highbd_apply_temporal_filter( + f->y_buffer + mb_y_src_offset, f->y_stride, predictor, BW, + f->u_buffer + mb_uv_src_offset, + f->v_buffer + mb_uv_src_offset, f->uv_stride, + predictor + BLK_PELS, predictor + (BLK_PELS << 1), + mb_uv_width, BW, BH, mbd->plane[1].subsampling_x, + mbd->plane[1].subsampling_y, adj_strength, blk_fw, + use_32x32, accumulator, count, accumulator + BLK_PELS, + count + BLK_PELS, accumulator + (BLK_PELS << 1), + count + (BLK_PELS << 1)); } } else { if (num_planes <= 1) { // Single plane case av1_temporal_filter_apply_c( - f->y_buffer + mb_y_offset, f->y_stride, predictor, BW, BH, - strength, blk_fw, use_32x32, accumulator, count); + f->y_buffer + mb_y_src_offset, f->y_stride, predictor, BW, + BH, strength, blk_fw, use_32x32, accumulator, count); } else { // Process 3 planes together. - apply_temporal_filter( - f->y_buffer + mb_y_offset, f->y_stride, predictor, BW, - f->u_buffer + mb_uv_offset, f->v_buffer + mb_uv_offset, - f->uv_stride, predictor + BLK_PELS, - predictor + (BLK_PELS << 1), mb_uv_width, BW, BH, - mbd->plane[1].subsampling_x, mbd->plane[1].subsampling_y, - strength, blk_fw, use_32x32, accumulator, count, - accumulator + BLK_PELS, count + BLK_PELS, - accumulator + (BLK_PELS << 1), count + (BLK_PELS << 1)); + av1_apply_temporal_filter( + f->y_buffer + mb_y_src_offset, f->y_stride, predictor, BW, + f->u_buffer + mb_uv_src_offset, + f->v_buffer + mb_uv_src_offset, f->uv_stride, + predictor + BLK_PELS, predictor + (BLK_PELS << 1), + mb_uv_width, BW, BH, mbd->plane[1].subsampling_x, + mbd->plane[1].subsampling_y, strength, blk_fw, use_32x32, + accumulator, count, accumulator + BLK_PELS, + count + BLK_PELS, accumulator + (BLK_PELS << 1), + count + (BLK_PELS << 1)); } } } @@ -1021,10 +1065,15 @@ static void temporal_filter_iterate_c(AV1_COMP *cpi, } } mb_y_offset += BW; + mb_y_src_offset += BW; mb_uv_offset += mb_uv_width; + mb_uv_src_offset += mb_uv_width; } - mb_y_offset += BH * f->y_stride - BW * mb_cols; - mb_uv_offset += mb_uv_height * f->uv_stride - mb_uv_width * mb_cols; + mb_y_offset += BH * cpi->alt_ref_buffer.y_stride - BW * mb_cols; + mb_y_src_offset += BH * f->y_stride - BW * mb_cols; + mb_uv_src_offset += mb_uv_height * f->uv_stride - mb_uv_width * mb_cols; + mb_uv_offset += + mb_uv_height * cpi->alt_ref_buffer.uv_stride - mb_uv_width * mb_cols; } // Restore input state @@ -1204,9 +1253,8 @@ void av1_temporal_filter(AV1_COMP *cpi, int distance) { // Apply context specific adjustments to the arnr filter parameters. if (gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE) { // TODO(weitinglin): Currently, we enforce the filtering strength on - // extra ARFs' to be zeros. We should investigate in which - // case it is more beneficial to use non-zero strength - // filtering. + // internal ARFs to be zeros. We should investigate in which case it is more + // beneficial to use non-zero strength filtering. strength = 0; frames_to_blur = 1; } else { diff --git a/third_party/aom/av1/encoder/tpl_model.c b/third_party/aom/av1/encoder/tpl_model.c index 3399116e9f..79afb6d17b 100644 --- a/third_party/aom/av1/encoder/tpl_model.c +++ b/third_party/aom/av1/encoder/tpl_model.c @@ -97,7 +97,7 @@ static uint32_t motion_compensated_prediction(AV1_COMP *cpi, ThreadData *td, av1_full_pixel_search(cpi, x, bsize, &best_ref_mv1_full, step_param, search_method, 0, sadpb, cond_cost_list(cpi, cost_list), &best_ref_mv1, INT_MAX, 0, (MI_SIZE * mi_col), - (MI_SIZE * mi_row), 0); + (MI_SIZE * mi_row), 0, &cpi->ss_cfg[SS_CFG_SRC]); /* restore UMV window */ x->mv_limits = tmp_mv_limits; @@ -119,7 +119,6 @@ static void mode_estimation(AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, tran_low_t *qcoeff, tran_low_t *dqcoeff, int mi_row, int mi_col, BLOCK_SIZE bsize, TX_SIZE tx_size, YV12_BUFFER_CONFIG *ref_frame[], uint8_t *predictor, - int64_t *recon_error, int64_t *sse, TplDepStats *tpl_stats) { AV1_COMMON *cm = &cpi->common; ThreadData *td = &cpi->td; @@ -223,11 +222,13 @@ static void mode_estimation(AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, inter_cost = aom_satd(coeff, pix_num); if (inter_cost < best_inter_cost) { + int64_t recon_error, sse; + best_rf_idx = rf_idx; best_inter_cost = inter_cost; best_mv.as_int = x->best_mv.as_int; - get_quantize_error(x, 0, coeff, qcoeff, dqcoeff, tx_size, recon_error, - sse); + get_quantize_error(x, 0, coeff, qcoeff, dqcoeff, tx_size, &recon_error, + &sse); } } best_intra_cost = AOMMAX(best_intra_cost, 1); @@ -325,9 +326,6 @@ static void tpl_model_update_b(TplDepFrame *tpl_frame, TplDepStats *tpl_stats, (ref_mi_col + idx)]; des_stats->mc_flow += (mc_flow * overlap_area) / pix_num; - des_stats->mc_ref_cost += - ((tpl_stats->intra_cost - tpl_stats->inter_cost) * overlap_area) / - pix_num; assert(overlap_area >= 0); } } @@ -395,19 +393,18 @@ static void mc_flow_dispenser(AV1_COMP *cpi, GF_PICTURE *gf_picture, MACROBLOCKD *xd = &x->e_mbd; int mi_row, mi_col; - DECLARE_ALIGNED(16, uint16_t, predictor16[32 * 32 * 3]); - DECLARE_ALIGNED(16, uint8_t, predictor8[32 * 32 * 3]); + DECLARE_ALIGNED(32, uint16_t, predictor16[32 * 32 * 3]); + DECLARE_ALIGNED(32, uint8_t, predictor8[32 * 32 * 3]); uint8_t *predictor; - DECLARE_ALIGNED(16, int16_t, src_diff[32 * 32]); - DECLARE_ALIGNED(16, tran_low_t, coeff[32 * 32]); - DECLARE_ALIGNED(16, tran_low_t, qcoeff[32 * 32]); - DECLARE_ALIGNED(16, tran_low_t, dqcoeff[32 * 32]); + DECLARE_ALIGNED(32, int16_t, src_diff[32 * 32]); + DECLARE_ALIGNED(32, tran_low_t, coeff[32 * 32]); + DECLARE_ALIGNED(32, tran_low_t, qcoeff[32 * 32]); + DECLARE_ALIGNED(32, tran_low_t, dqcoeff[32 * 32]); const BLOCK_SIZE bsize = BLOCK_32X32; const TX_SIZE tx_size = max_txsize_lookup[bsize]; const int mi_height = mi_size_high[bsize]; const int mi_width = mi_size_wide[bsize]; - int64_t recon_error, sse; // Setup scaling factor av1_setup_scale_factors_for_frame( @@ -433,8 +430,8 @@ static void mc_flow_dispenser(AV1_COMP *cpi, GF_PICTURE *gf_picture, // Get rd multiplier set up. rdmult = (int)av1_compute_rd_mult(cpi, tpl_frame->base_qindex); if (rdmult < 1) rdmult = 1; - set_error_per_bit(&cpi->td.mb, rdmult); - av1_initialize_me_consts(cpi, &cpi->td.mb, tpl_frame->base_qindex); + set_error_per_bit(x, rdmult); + av1_initialize_me_consts(cpi, x, tpl_frame->base_qindex); tpl_frame->is_valid = 1; @@ -450,7 +447,7 @@ static void mc_flow_dispenser(AV1_COMP *cpi, GF_PICTURE *gf_picture, TplDepStats tpl_stats; mode_estimation(cpi, x, xd, &sf, gf_picture, frame_idx, src_diff, coeff, qcoeff, dqcoeff, mi_row, mi_col, bsize, tx_size, - ref_frame, predictor, &recon_error, &sse, &tpl_stats); + ref_frame, predictor, &tpl_stats); // Motion flow dependency dispenser. tpl_model_store(tpl_frame->tpl_stats_ptr, mi_row, mi_col, bsize, diff --git a/third_party/aom/av1/encoder/var_based_part.c b/third_party/aom/av1/encoder/var_based_part.c new file mode 100644 index 0000000000..3cead914ac --- /dev/null +++ b/third_party/aom/av1/encoder/var_based_part.c @@ -0,0 +1,778 @@ +/* + * Copyright (c) 2019, 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 +#include +#include +#include + +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" +#include "config/av1_rtcd.h" + +#include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/binary_codes_writer.h" +#include "aom_ports/mem.h" +#include "aom_ports/aom_timer.h" +#include "aom_ports/system_state.h" + +#include "av1/common/reconinter.h" +#include "av1/common/blockd.h" + +#include "av1/encoder/encodeframe.h" +#include "av1/encoder/var_based_part.h" +#include "av1/encoder/reconinter_enc.h" + +extern const uint8_t AV1_VAR_OFFS[]; + +typedef struct { + // TODO(kyslov): consider changing to 64bit + + // This struct is used for computing variance in choose_partitioning(), where + // the max number of samples within a superblock is 32x32 (with 4x4 avg). + // With 8bit bitdepth, uint32_t is enough for sum_square_error (2^8 * 2^8 * 32 + // * 32 = 2^26). For high bitdepth we need to consider changing this to 64 bit + uint32_t sum_square_error; + int32_t sum_error; + int log2_count; + int variance; +} var; + +typedef struct { + var none; + var horz[2]; + var vert[2]; +} partition_variance; + +typedef struct { + partition_variance part_variances; + var split[4]; +} v4x4; + +typedef struct { + partition_variance part_variances; + v4x4 split[4]; +} v8x8; + +typedef struct { + partition_variance part_variances; + v8x8 split[4]; +} v16x16; + +typedef struct { + partition_variance part_variances; + v16x16 split[4]; +} v32x32; + +typedef struct { + partition_variance part_variances; + v32x32 split[4]; +} v64x64; + +typedef struct { + partition_variance part_variances; + v64x64 split[4]; +} v128x128; + +typedef struct { + partition_variance *part_variances; + var *split[4]; +} variance_node; + +static void tree_to_node(void *data, BLOCK_SIZE bsize, variance_node *node) { + int i; + node->part_variances = NULL; + switch (bsize) { + case BLOCK_128X128: { + v128x128 *vt = (v128x128 *)data; + node->part_variances = &vt->part_variances; + for (i = 0; i < 4; i++) + node->split[i] = &vt->split[i].part_variances.none; + break; + } + case BLOCK_64X64: { + v64x64 *vt = (v64x64 *)data; + node->part_variances = &vt->part_variances; + for (i = 0; i < 4; i++) + node->split[i] = &vt->split[i].part_variances.none; + break; + } + case BLOCK_32X32: { + v32x32 *vt = (v32x32 *)data; + node->part_variances = &vt->part_variances; + for (i = 0; i < 4; i++) + node->split[i] = &vt->split[i].part_variances.none; + break; + } + case BLOCK_16X16: { + v16x16 *vt = (v16x16 *)data; + node->part_variances = &vt->part_variances; + for (i = 0; i < 4; i++) + node->split[i] = &vt->split[i].part_variances.none; + break; + } + case BLOCK_8X8: { + v8x8 *vt = (v8x8 *)data; + node->part_variances = &vt->part_variances; + for (i = 0; i < 4; i++) + node->split[i] = &vt->split[i].part_variances.none; + break; + } + default: { + v4x4 *vt = (v4x4 *)data; + assert(bsize == BLOCK_4X4); + node->part_variances = &vt->part_variances; + for (i = 0; i < 4; i++) node->split[i] = &vt->split[i]; + break; + } + } +} + +// Set variance values given sum square error, sum error, count. +static void fill_variance(uint32_t s2, int32_t s, int c, var *v) { + v->sum_square_error = s2; + v->sum_error = s; + v->log2_count = c; +} + +static void get_variance(var *v) { + v->variance = + (int)(256 * (v->sum_square_error - + (uint32_t)(((int64_t)v->sum_error * v->sum_error) >> + v->log2_count)) >> + v->log2_count); +} + +static void sum_2_variances(const var *a, const var *b, var *r) { + assert(a->log2_count == b->log2_count); + fill_variance(a->sum_square_error + b->sum_square_error, + a->sum_error + b->sum_error, a->log2_count + 1, r); +} + +static void fill_variance_tree(void *data, BLOCK_SIZE bsize) { + variance_node node; + memset(&node, 0, sizeof(node)); + tree_to_node(data, bsize, &node); + sum_2_variances(node.split[0], node.split[1], &node.part_variances->horz[0]); + sum_2_variances(node.split[2], node.split[3], &node.part_variances->horz[1]); + sum_2_variances(node.split[0], node.split[2], &node.part_variances->vert[0]); + sum_2_variances(node.split[1], node.split[3], &node.part_variances->vert[1]); + sum_2_variances(&node.part_variances->vert[0], &node.part_variances->vert[1], + &node.part_variances->none); +} + +static void set_block_size(AV1_COMP *const cpi, MACROBLOCK *const x, + MACROBLOCKD *const xd, int mi_row, int mi_col, + BLOCK_SIZE bsize) { + if (cpi->common.mi_cols > mi_col && cpi->common.mi_rows > mi_row) { + set_mode_info_offsets(cpi, x, xd, mi_row, mi_col); + xd->mi[0]->sb_type = bsize; + } +} + +static int set_vt_partitioning(AV1_COMP *cpi, MACROBLOCK *const x, + MACROBLOCKD *const xd, + const TileInfo *const tile, void *data, + BLOCK_SIZE bsize, int mi_row, int mi_col, + int64_t threshold, BLOCK_SIZE bsize_min, + int force_split) { + AV1_COMMON *const cm = &cpi->common; + variance_node vt; + const int block_width = mi_size_wide[bsize]; + const int block_height = mi_size_high[bsize]; + + assert(block_height == block_width); + tree_to_node(data, bsize, &vt); + + if (force_split == 1) return 0; + + if (mi_col + block_width > tile->mi_col_end || + mi_row + block_height > tile->mi_row_end) + return 0; + + // For bsize=bsize_min (16x16/8x8 for 8x8/4x4 downsampling), select if + // variance is below threshold, otherwise split will be selected. + // No check for vert/horiz split as too few samples for variance. + if (bsize == bsize_min) { + // Variance already computed to set the force_split. + if (frame_is_intra_only(cm)) get_variance(&vt.part_variances->none); + if (mi_col + block_width / 2 < cm->mi_cols && + mi_row + block_height / 2 < cm->mi_rows && + vt.part_variances->none.variance < threshold) { + set_block_size(cpi, x, xd, mi_row, mi_col, bsize); + return 1; + } + return 0; + } else if (bsize > bsize_min) { + // Variance already computed to set the force_split. + if (frame_is_intra_only(cm)) get_variance(&vt.part_variances->none); + // For key frame: take split for bsize above 32X32 or very high variance. + if (frame_is_intra_only(cm) && + (bsize > BLOCK_32X32 || + vt.part_variances->none.variance > (threshold << 4))) { + return 0; + } + // If variance is low, take the bsize (no split). + if (mi_col + block_width / 2 < cm->mi_cols && + mi_row + block_height / 2 < cm->mi_rows && + vt.part_variances->none.variance < threshold) { + set_block_size(cpi, x, xd, mi_row, mi_col, bsize); + return 1; + } + + // Check vertical split. + if (mi_row + block_height / 2 < cm->mi_rows) { + BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_VERT); + get_variance(&vt.part_variances->vert[0]); + get_variance(&vt.part_variances->vert[1]); + if (vt.part_variances->vert[0].variance < threshold && + vt.part_variances->vert[1].variance < threshold && + get_plane_block_size(subsize, xd->plane[1].subsampling_x, + xd->plane[1].subsampling_y) < BLOCK_INVALID) { + set_block_size(cpi, x, xd, mi_row, mi_col, subsize); + set_block_size(cpi, x, xd, mi_row, mi_col + block_width / 2, subsize); + return 1; + } + } + // Check horizontal split. + if (mi_col + block_width / 2 < cm->mi_cols) { + BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_HORZ); + get_variance(&vt.part_variances->horz[0]); + get_variance(&vt.part_variances->horz[1]); + if (vt.part_variances->horz[0].variance < threshold && + vt.part_variances->horz[1].variance < threshold && + get_plane_block_size(subsize, xd->plane[1].subsampling_x, + xd->plane[1].subsampling_y) < BLOCK_INVALID) { + set_block_size(cpi, x, xd, mi_row, mi_col, subsize); + set_block_size(cpi, x, xd, mi_row + block_height / 2, mi_col, subsize); + return 1; + } + } + + return 0; + } + return 0; +} + +static void fill_variance_8x8avg(const uint8_t *s, int sp, const uint8_t *d, + int dp, int x16_idx, int y16_idx, v16x16 *vst, + int pixels_wide, int pixels_high, + int is_key_frame) { + int k; + for (k = 0; k < 4; k++) { + int x8_idx = x16_idx + ((k & 1) << 3); + int y8_idx = y16_idx + ((k >> 1) << 3); + unsigned int sse = 0; + int sum = 0; + if (x8_idx < pixels_wide && y8_idx < pixels_high) { + int s_avg; + int d_avg = 128; + s_avg = aom_avg_8x8(s + y8_idx * sp + x8_idx, sp); + if (!is_key_frame) d_avg = aom_avg_8x8(d + y8_idx * dp + x8_idx, dp); + + sum = s_avg - d_avg; + sse = sum * sum; + } + fill_variance(sse, sum, 0, &vst->split[k].part_variances.none); + } +} + +static int compute_minmax_8x8(const uint8_t *s, int sp, const uint8_t *d, + int dp, int x16_idx, int y16_idx, int pixels_wide, + int pixels_high) { + int k; + int minmax_max = 0; + int minmax_min = 255; + // Loop over the 4 8x8 subblocks. + for (k = 0; k < 4; k++) { + int x8_idx = x16_idx + ((k & 1) << 3); + int y8_idx = y16_idx + ((k >> 1) << 3); + int min = 0; + int max = 0; + if (x8_idx < pixels_wide && y8_idx < pixels_high) { + aom_minmax_8x8(s + y8_idx * sp + x8_idx, sp, d + y8_idx * dp + x8_idx, dp, + &min, &max); + if ((max - min) > minmax_max) minmax_max = (max - min); + if ((max - min) < minmax_min) minmax_min = (max - min); + } + } + return (minmax_max - minmax_min); +} + +static void fill_variance_4x4avg(const uint8_t *s, int sp, const uint8_t *d, + int dp, int x8_idx, int y8_idx, v8x8 *vst, + int pixels_wide, int pixels_high, + int is_key_frame) { + int k; + for (k = 0; k < 4; k++) { + int x4_idx = x8_idx + ((k & 1) << 2); + int y4_idx = y8_idx + ((k >> 1) << 2); + unsigned int sse = 0; + int sum = 0; + if (x4_idx < pixels_wide && y4_idx < pixels_high) { + int s_avg; + int d_avg = 128; + s_avg = aom_avg_4x4(s + y4_idx * sp + x4_idx, sp); + if (!is_key_frame) d_avg = aom_avg_4x4(d + y4_idx * dp + x4_idx, dp); + sum = s_avg - d_avg; + sse = sum * sum; + } + fill_variance(sse, sum, 0, &vst->split[k].part_variances.none); + } +} + +static int64_t scale_part_thresh_sumdiff(int64_t threshold_base, int speed, + int width, int height, + int content_state) { + if (speed >= 8) { + if (width <= 640 && height <= 480) + return (5 * threshold_base) >> 2; + else if ((content_state == kLowSadLowSumdiff) || + (content_state == kHighSadLowSumdiff) || + (content_state == kLowVarHighSumdiff)) + return (5 * threshold_base) >> 2; + } else if (speed == 7) { + if ((content_state == kLowSadLowSumdiff) || + (content_state == kHighSadLowSumdiff) || + (content_state == kLowVarHighSumdiff)) { + return (5 * threshold_base) >> 2; + } + } + return threshold_base; +} + +// Set the variance split thresholds for following the block sizes: +// 0 - threshold_128x128, 1 - threshold_64x64, 2 - threshold_32x32, +// 3 - vbp_threshold_16x16. 4 - vbp_threshold_8x8 (to split to 4x4 partition) is +// currently only used on key frame. +static void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[], int q, + int content_state) { + AV1_COMMON *const cm = &cpi->common; + const int is_key_frame = frame_is_intra_only(cm); + const int threshold_multiplier = is_key_frame ? 40 : 1; + int64_t threshold_base = + (int64_t)(threshold_multiplier * cpi->dequants.y_dequant_QTX[q][1]); + + if (is_key_frame) { + thresholds[0] = threshold_base; + thresholds[1] = threshold_base; + thresholds[2] = threshold_base >> 2; + thresholds[3] = threshold_base >> 2; + thresholds[4] = threshold_base << 2; + } else { + // Increase base variance threshold based on content_state/sum_diff level. + threshold_base = scale_part_thresh_sumdiff( + threshold_base, cpi->oxcf.speed, cm->width, cm->height, content_state); + + thresholds[1] = threshold_base; + thresholds[3] = threshold_base << cpi->oxcf.speed; + if (cm->width >= 1280 && cm->height >= 720) + thresholds[3] = thresholds[3] << 1; + if (cm->width <= 352 && cm->height <= 288) { + thresholds[1] = threshold_base >> 3; + thresholds[2] = threshold_base >> 1; + thresholds[3] = threshold_base << 3; + } else if (cm->width < 1280 && cm->height < 720) { + thresholds[2] = (5 * threshold_base) >> 2; + } else if (cm->width < 1920 && cm->height < 1080) { + thresholds[2] = threshold_base << 1; + thresholds[3] <<= 2; + } else { + thresholds[2] = (5 * threshold_base) >> 1; + } + } +} + +void av1_set_variance_partition_thresholds(AV1_COMP *cpi, int q, + int content_state) { + AV1_COMMON *const cm = &cpi->common; + SPEED_FEATURES *const sf = &cpi->sf; + const int is_key_frame = frame_is_intra_only(cm); + if (sf->partition_search_type != VAR_BASED_PARTITION) { + return; + } else { + set_vbp_thresholds(cpi, cpi->vbp_thresholds, q, content_state); + // The thresholds below are not changed locally. + if (is_key_frame) { + cpi->vbp_threshold_sad = 0; + cpi->vbp_threshold_copy = 0; + cpi->vbp_bsize_min = BLOCK_8X8; + } else { + if (cm->width <= 352 && cm->height <= 288) + cpi->vbp_threshold_sad = 10; + else + cpi->vbp_threshold_sad = (cpi->dequants.y_dequant_QTX[q][1] << 1) > 1000 + ? (cpi->dequants.y_dequant_QTX[q][1] << 1) + : 1000; + cpi->vbp_bsize_min = BLOCK_16X16; + if (cm->width <= 352 && cm->height <= 288) + cpi->vbp_threshold_copy = 4000; + else if (cm->width <= 640 && cm->height <= 360) + cpi->vbp_threshold_copy = 8000; + else + cpi->vbp_threshold_copy = + (cpi->dequants.y_dequant_QTX[q][1] << 3) > 8000 + ? (cpi->dequants.y_dequant_QTX[q][1] << 3) + : 8000; + } + cpi->vbp_threshold_minmax = 15 + (q >> 3); + } +} + +// This function chooses partitioning based on the variance between source and +// reconstructed last, where variance is computed for down-sampled inputs. +// TODO(kyslov): lot of things. Bring back noise estimation, brush up partition +// selection and most of all - retune the thresholds +int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, + MACROBLOCK *x, int mi_row, int mi_col) { + AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + + int i, j, k, m; + v128x128 *vt; + v16x16 *vt2 = NULL; + unsigned char force_split[85]; + int avg_32x32; + int max_var_32x32 = 0; + int min_var_32x32 = INT_MAX; + int var_32x32; + int var_64x64; + int min_var_64x64 = INT_MAX; + int max_var_64x64 = 0; + int avg_16x16[4]; + int maxvar_16x16[4]; + int minvar_16x16[4]; + int64_t threshold_4x4avg; + int content_state = 0; + uint8_t *s; + const uint8_t *d; + int sp; + int dp; + int compute_minmax_variance = 1; + int is_key_frame = frame_is_intra_only(cm); + int pixels_wide = 128, pixels_high = 128; + assert(cm->seq_params.sb_size == BLOCK_64X64 || + cm->seq_params.sb_size == BLOCK_128X128); + const int is_small_sb = (cm->seq_params.sb_size == BLOCK_64X64); + const int num_64x64_blocks = is_small_sb ? 1 : 4; + + CHECK_MEM_ERROR(cm, vt, aom_calloc(1, sizeof(*vt))); + + int64_t thresholds[5] = { cpi->vbp_thresholds[0], cpi->vbp_thresholds[1], + cpi->vbp_thresholds[2], cpi->vbp_thresholds[3], + cpi->vbp_thresholds[4] }; + + const int low_res = (cm->width <= 352 && cm->height <= 288); + int variance4x4downsample[64]; + int segment_id; + const int num_planes = av1_num_planes(cm); + + segment_id = xd->mi[0]->segment_id; + + set_vbp_thresholds(cpi, thresholds, cm->base_qindex, content_state); + + if (is_small_sb) { + pixels_wide = 64; + pixels_high = 64; + } + + // For non keyframes, disable 4x4 average for low resolution when speed = 8 + threshold_4x4avg = INT64_MAX; + + if (xd->mb_to_right_edge < 0) pixels_wide += (xd->mb_to_right_edge >> 3); + if (xd->mb_to_bottom_edge < 0) pixels_high += (xd->mb_to_bottom_edge >> 3); + + s = x->plane[0].src.buf; + sp = x->plane[0].src.stride; + + // Index for force_split: 0 for 64x64, 1-4 for 32x32 blocks, + // 5-20 for the 16x16 blocks. + force_split[0] = 0; + + if (!is_key_frame) { + // TODO(kyslov): we are assuming that the ref is LAST_FRAME! Check if it + // is!! + MB_MODE_INFO *mi = xd->mi[0]; + const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, LAST_FRAME); + + assert(yv12 != NULL); + + av1_setup_pre_planes(xd, 0, yv12, mi_row, mi_col, + get_ref_scale_factors(cm, LAST_FRAME), num_planes); + mi->ref_frame[0] = LAST_FRAME; + mi->ref_frame[1] = NONE_FRAME; + mi->sb_type = cm->seq_params.sb_size; + mi->mv[0].as_int = 0; + mi->interp_filters = av1_make_interp_filters(BILINEAR, BILINEAR); + if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) { + const MV dummy_mv = { 0, 0 }; + av1_int_pro_motion_estimation(cpi, x, cm->seq_params.sb_size, mi_row, + mi_col, &dummy_mv); + } + +// TODO(kyslov): bring the small SAD functionality back +#if 0 + y_sad = cpi->fn_ptr[bsize].sdf(x->plane[0].src.buf, x->plane[0].src.stride, + xd->plane[0].pre[0].buf, + xd->plane[0].pre[0].stride); +#endif + x->pred_mv[LAST_FRAME] = mi->mv[0].as_mv; + + set_ref_ptrs(cm, xd, mi->ref_frame[0], mi->ref_frame[1]); + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, + cm->seq_params.sb_size, AOM_PLANE_Y, + AOM_PLANE_Y); + + d = xd->plane[0].dst.buf; + dp = xd->plane[0].dst.stride; + + // If the y_sad is very small, take 64x64 as partition and exit. + // Don't check on boosted segment for now, as 64x64 is suppressed there. +#if 0 + if (segment_id == CR_SEGMENT_ID_BASE && y_sad < cpi->vbp_threshold_sad) + { const int block_width = num_8x8_blocks_wide_lookup[BLOCK_64X64]; const + int block_height = num_8x8_blocks_high_lookup[BLOCK_64X64]; if (mi_col + + block_width / 2 < cm->mi_cols && mi_row + block_height / 2 < cm->mi_rows) + { set_block_size(cpi, x, xd, mi_row, mi_col, BLOCK_128X128); + x->variance_low[0] = 1; + return 0; + } + } +#endif + } else { + d = AV1_VAR_OFFS; + dp = 0; + } + + if (low_res && threshold_4x4avg < INT64_MAX) + CHECK_MEM_ERROR(cm, vt2, aom_calloc(64, sizeof(*vt2))); + // Fill in the entire tree of 8x8 (or 4x4 under some conditions) variances + // for splits. + for (m = 0; m < num_64x64_blocks; m++) { + const int x64_idx = ((m & 1) << 6); + const int y64_idx = ((m >> 1) << 6); + const int m2 = m << 2; + force_split[m + 1] = 0; + for (i = 0; i < 4; i++) { + const int x32_idx = x64_idx + ((i & 1) << 5); + const int y32_idx = y64_idx + ((i >> 1) << 5); + const int i2 = (m2 + i) << 2; + force_split[5 + m2 + i] = 0; + avg_16x16[i] = 0; + maxvar_16x16[i] = 0; + minvar_16x16[i] = INT_MAX; + for (j = 0; j < 4; j++) { + const int x16_idx = x32_idx + ((j & 1) << 4); + const int y16_idx = y32_idx + ((j >> 1) << 4); + const int split_index = 21 + i2 + j; + v16x16 *vst = &vt->split[m].split[i].split[j]; + force_split[split_index] = 0; + variance4x4downsample[i2 + j] = 0; + if (!is_key_frame) { + fill_variance_8x8avg(s, sp, d, dp, x16_idx, y16_idx, vst, pixels_wide, + pixels_high, is_key_frame); + fill_variance_tree(&vt->split[m].split[i].split[j], BLOCK_16X16); + get_variance(&vt->split[m].split[i].split[j].part_variances.none); + avg_16x16[i] += + vt->split[m].split[i].split[j].part_variances.none.variance; + if (vt->split[m].split[i].split[j].part_variances.none.variance < + minvar_16x16[i]) + minvar_16x16[i] = + vt->split[m].split[i].split[j].part_variances.none.variance; + if (vt->split[m].split[i].split[j].part_variances.none.variance > + maxvar_16x16[i]) + maxvar_16x16[i] = + vt->split[m].split[i].split[j].part_variances.none.variance; + if (vt->split[m].split[i].split[j].part_variances.none.variance > + thresholds[3]) { + // 16X16 variance is above threshold for split, so force split to + // 8x8 for this 16x16 block (this also forces splits for upper + // levels). + force_split[split_index] = 1; + force_split[5 + m2 + i] = 1; + force_split[m + 1] = 1; + force_split[0] = 1; + } else if (compute_minmax_variance && + vt->split[m] + .split[i] + .split[j] + .part_variances.none.variance > thresholds[2] && + !cyclic_refresh_segment_id_boosted(segment_id)) { + // We have some nominal amount of 16x16 variance (based on average), + // compute the minmax over the 8x8 sub-blocks, and if above + // threshold, force split to 8x8 block for this 16x16 block. + int minmax = compute_minmax_8x8(s, sp, d, dp, x16_idx, y16_idx, + pixels_wide, pixels_high); + int thresh_minmax = (int)cpi->vbp_threshold_minmax; + if (minmax > thresh_minmax) { + force_split[split_index] = 1; + force_split[5 + m2 + i] = 1; + force_split[m + 1] = 1; + force_split[0] = 1; + } + } + } + if (is_key_frame) { + force_split[split_index] = 0; + // Go down to 4x4 down-sampling for variance. + variance4x4downsample[i2 + j] = 1; + for (k = 0; k < 4; k++) { + int x8_idx = x16_idx + ((k & 1) << 3); + int y8_idx = y16_idx + ((k >> 1) << 3); + v8x8 *vst2 = is_key_frame ? &vst->split[k] : &vt2[i2 + j].split[k]; + fill_variance_4x4avg(s, sp, d, dp, x8_idx, y8_idx, vst2, + pixels_wide, pixels_high, is_key_frame); + } + } + } + } + } + + // Fill the rest of the variance tree by summing split partition values. + for (m = 0; m < num_64x64_blocks; ++m) { + avg_32x32 = 0; + const int m2 = m << 2; + for (i = 0; i < 4; i++) { + const int i2 = (m2 + i) << 2; + for (j = 0; j < 4; j++) { + const int split_index = 21 + i2 + j; + if (variance4x4downsample[i2 + j] == 1) { + v16x16 *vtemp = + (!is_key_frame) ? &vt2[i2 + j] : &vt->split[m].split[i].split[j]; + for (k = 0; k < 4; k++) + fill_variance_tree(&vtemp->split[k], BLOCK_8X8); + fill_variance_tree(vtemp, BLOCK_16X16); + // If variance of this 16x16 block is above the threshold, force block + // to split. This also forces a split on the upper levels. + get_variance(&vtemp->part_variances.none); + if (vtemp->part_variances.none.variance > thresholds[3]) { + force_split[split_index] = 1; + force_split[5 + m2 + i] = 1; + force_split[m + 1] = 1; + force_split[0] = 1; + } + } + } + fill_variance_tree(&vt->split[m].split[i], BLOCK_32X32); + // If variance of this 32x32 block is above the threshold, or if its above + // (some threshold of) the average variance over the sub-16x16 blocks, + // then force this block to split. This also forces a split on the upper + // (64x64) level. + if (!force_split[5 + m2 + i]) { + get_variance(&vt->split[m].split[i].part_variances.none); + var_32x32 = vt->split[m].split[i].part_variances.none.variance; + max_var_32x32 = AOMMAX(var_32x32, max_var_32x32); + min_var_32x32 = AOMMIN(var_32x32, min_var_32x32); + if (vt->split[m].split[i].part_variances.none.variance > + thresholds[2] || + (!is_key_frame && + vt->split[m].split[i].part_variances.none.variance > + (thresholds[2] >> 1) && + vt->split[m].split[i].part_variances.none.variance > + (avg_16x16[i] >> 1))) { + force_split[5 + m2 + i] = 1; + force_split[m + 1] = 1; + force_split[0] = 1; + } else if (!is_key_frame && cm->height <= 360 && + (maxvar_16x16[i] - minvar_16x16[i]) > (thresholds[2] >> 1) && + maxvar_16x16[i] > thresholds[2]) { + force_split[5 + m2 + i] = 1; + force_split[m + 1] = 1; + force_split[0] = 1; + } + avg_32x32 += var_32x32; + } + } + if (!force_split[1 + m]) { + fill_variance_tree(&vt->split[m], BLOCK_64X64); + get_variance(&vt->split[m].part_variances.none); + var_64x64 = vt->split[m].part_variances.none.variance; + max_var_64x64 = AOMMAX(var_64x64, max_var_64x64); + min_var_64x64 = AOMMIN(var_64x64, min_var_64x64); + // If variance of this 64x64 block is above (some threshold of) the + // average variance over the sub-32x32 blocks, then force this block to + // split. Only checking this for noise level >= medium for now. + + if (!is_key_frame && + (max_var_32x32 - min_var_32x32) > 3 * (thresholds[1] >> 3) && + max_var_32x32 > thresholds[1] >> 1) + force_split[1 + m] = 1; + } + if (is_small_sb) force_split[0] = 1; + } + + if (!force_split[0]) { + fill_variance_tree(vt, BLOCK_128X128); + get_variance(&vt->part_variances.none); + if (!is_key_frame && + (max_var_64x64 - min_var_64x64) > 3 * (thresholds[0] >> 3) && + max_var_64x64 > thresholds[0] >> 1) + force_split[0] = 1; + } + + if (!set_vt_partitioning(cpi, x, xd, tile, vt, BLOCK_128X128, mi_row, mi_col, + thresholds[0], BLOCK_16X16, force_split[0])) { + for (m = 0; m < num_64x64_blocks; ++m) { + const int x64_idx = ((m & 1) << 4); + const int y64_idx = ((m >> 1) << 4); + const int m2 = m << 2; + + // Now go through the entire structure, splitting every block size until + // we get to one that's got a variance lower than our threshold. + if (!set_vt_partitioning(cpi, x, xd, tile, &vt->split[m], BLOCK_64X64, + mi_row + y64_idx, mi_col + x64_idx, + thresholds[1], BLOCK_16X16, + force_split[1 + m])) { + for (i = 0; i < 4; ++i) { + const int x32_idx = ((i & 1) << 3); + const int y32_idx = ((i >> 1) << 3); + const int i2 = (m2 + i) << 2; + if (!set_vt_partitioning(cpi, x, xd, tile, &vt->split[m].split[i], + BLOCK_32X32, (mi_row + y64_idx + y32_idx), + (mi_col + x64_idx + x32_idx), thresholds[2], + BLOCK_16X16, force_split[5 + m2 + i])) { + for (j = 0; j < 4; ++j) { + const int x16_idx = ((j & 1) << 2); + const int y16_idx = ((j >> 1) << 2); + const int split_index = 21 + i2 + j; + // For inter frames: if variance4x4downsample[] == 1 for this + // 16x16 block, then the variance is based on 4x4 down-sampling, + // so use vt2 in set_vt_partioning(), otherwise use vt. + v16x16 *vtemp = + (!is_key_frame && variance4x4downsample[i2 + j] == 1) + ? &vt2[i2 + j] + : &vt->split[m].split[i].split[j]; + if (!set_vt_partitioning(cpi, x, xd, tile, vtemp, BLOCK_16X16, + mi_row + y64_idx + y32_idx + y16_idx, + mi_col + x64_idx + x32_idx + x16_idx, + thresholds[3], BLOCK_8X8, + force_split[split_index])) { + for (k = 0; k < 4; ++k) { + const int x8_idx = (k & 1) << 1; + const int y8_idx = (k >> 1) << 1; + set_block_size( + cpi, x, xd, + (mi_row + y64_idx + y32_idx + y16_idx + y8_idx), + (mi_col + x64_idx + x32_idx + x16_idx + x8_idx), + BLOCK_8X8); + } + } + } + } + } + } + } + } + + if (vt2) aom_free(vt2); + if (vt) aom_free(vt); + return 0; +} diff --git a/third_party/aom/av1/encoder/var_based_part.h b/third_party/aom/av1/encoder/var_based_part.h new file mode 100644 index 0000000000..c35522442a --- /dev/null +++ b/third_party/aom/av1/encoder/var_based_part.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, 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. + */ + +#ifndef AOM_AV1_ENCODER_VAR_BASED_PART_H_ +#define AOM_AV1_ENCODER_VAR_BASED_PART_H_ + +#include + +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" +#include "config/av1_rtcd.h" + +#include "av1/encoder/encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void av1_set_variance_partition_thresholds(AV1_COMP *cpi, int q, + int content_state); + +int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, + MACROBLOCK *x, int mi_row, int mi_col); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_VAR_BASED_PART_H_ diff --git a/third_party/aom/av1/encoder/x86/av1_fwd_txfm2d_avx2.c b/third_party/aom/av1/encoder/x86/av1_fwd_txfm2d_avx2.c index 13982ccbb9..9483063bd6 100644 --- a/third_party/aom/av1/encoder/x86/av1_fwd_txfm2d_avx2.c +++ b/third_party/aom/av1/encoder/x86/av1_fwd_txfm2d_avx2.c @@ -1408,12 +1408,6 @@ static INLINE void fadst16x16_new_avx2(const __m256i *input, __m256i *output, output[15] = x1[0]; } -static INLINE __m256i scale_round_avx2(const __m256i a, const int scale) { - const __m256i scale__r = pair_set_w16_epi16(scale, 1 << (NewSqrt2Bits - 1)); - const __m256i b = _mm256_madd_epi16(a, scale__r); - return _mm256_srai_epi32(b, NewSqrt2Bits); -} - static INLINE void fidentity16x16_new_avx2(const __m256i *input, __m256i *output, int8_t cos_bit) { (void)cos_bit; @@ -1997,6 +1991,794 @@ static void lowbd_fwd_txfm2d_64x16_avx2(const int16_t *input, int32_t *output, } } +static INLINE void btf_16_avx2(__m256i *w0, __m256i *w1, __m256i *in0, + __m256i *in1, __m128i *out0, __m128i *out1, + __m128i *out2, __m128i *out3, + const __m256i *__rounding, int8_t *cos_bit) { + __m256i t0 = _mm256_unpacklo_epi16(*in0, *in1); + __m256i t1 = _mm256_unpackhi_epi16(*in0, *in1); + __m256i u0 = _mm256_madd_epi16(t0, *w0); + __m256i u1 = _mm256_madd_epi16(t1, *w0); + __m256i v0 = _mm256_madd_epi16(t0, *w1); + __m256i v1 = _mm256_madd_epi16(t1, *w1); + + __m256i a0 = _mm256_add_epi32(u0, *__rounding); + __m256i a1 = _mm256_add_epi32(u1, *__rounding); + __m256i b0 = _mm256_add_epi32(v0, *__rounding); + __m256i b1 = _mm256_add_epi32(v1, *__rounding); + + __m256i c0 = _mm256_srai_epi32(a0, *cos_bit); + __m256i c1 = _mm256_srai_epi32(a1, *cos_bit); + __m256i d0 = _mm256_srai_epi32(b0, *cos_bit); + __m256i d1 = _mm256_srai_epi32(b1, *cos_bit); + + __m256i temp0 = _mm256_packs_epi32(c0, c1); + __m256i temp1 = _mm256_packs_epi32(d0, d1); + + *out0 = _mm256_castsi256_si128(temp0); + *out1 = _mm256_castsi256_si128(temp1); + *out2 = _mm256_extracti128_si256(temp0, 0x01); + *out3 = _mm256_extracti128_si256(temp1, 0x01); +} + +static INLINE void fdct8x8_new_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { + const int32_t *cospi = cospi_arr(cos_bit); + const __m256i __rounding = _mm256_set1_epi32(1 << (cos_bit - 1)); + + __m256i cospi_m32_p32 = pair_set_w16_epi16(-cospi[32], cospi[32]); + __m256i cospi_p32_p32 = pair_set_w16_epi16(cospi[32], cospi[32]); + __m256i cospi_p32_m32 = pair_set_w16_epi16(cospi[32], -cospi[32]); + __m256i cospi_p48_p16 = pair_set_w16_epi16(cospi[48], cospi[16]); + __m256i cospi_m16_p48 = pair_set_w16_epi16(-cospi[16], cospi[48]); + __m256i cospi_p56_p08 = pair_set_w16_epi16(cospi[56], cospi[8]); + __m256i cospi_m08_p56 = pair_set_w16_epi16(-cospi[8], cospi[56]); + __m256i cospi_p24_p40 = pair_set_w16_epi16(cospi[24], cospi[40]); + __m256i cospi_m40_p24 = pair_set_w16_epi16(-cospi[40], cospi[24]); + + // stage 1 + __m256i x1[8]; + x1[0] = _mm256_adds_epi16(input[0], input[7]); + x1[7] = _mm256_subs_epi16(input[0], input[7]); + x1[1] = _mm256_adds_epi16(input[1], input[6]); + x1[6] = _mm256_subs_epi16(input[1], input[6]); + x1[2] = _mm256_adds_epi16(input[2], input[5]); + x1[5] = _mm256_subs_epi16(input[2], input[5]); + x1[3] = _mm256_adds_epi16(input[3], input[4]); + x1[4] = _mm256_subs_epi16(input[3], input[4]); + + // stage 2 + __m256i x2[8]; + x2[0] = _mm256_adds_epi16(x1[0], x1[3]); + x2[3] = _mm256_subs_epi16(x1[0], x1[3]); + x2[1] = _mm256_adds_epi16(x1[1], x1[2]); + x2[2] = _mm256_subs_epi16(x1[1], x1[2]); + x2[4] = x1[4]; + btf_16_w16_avx2(cospi_m32_p32, cospi_p32_p32, &x1[5], &x1[6], __rounding, + cos_bit); + x2[5] = x1[5]; + x2[6] = x1[6]; + x2[7] = x1[7]; + + // stage 3 + __m256i x3[8]; + btf_16_w16_avx2(cospi_p32_p32, cospi_p32_m32, &x2[0], &x2[1], __rounding, + cos_bit); + x3[0] = x2[0]; + x3[1] = x2[1]; + btf_16_w16_avx2(cospi_p48_p16, cospi_m16_p48, &x2[2], &x2[3], __rounding, + cos_bit); + x3[2] = x2[2]; + x3[3] = x2[3]; + x3[4] = _mm256_adds_epi16(x2[4], x2[5]); + x3[5] = _mm256_subs_epi16(x2[4], x2[5]); + x3[6] = _mm256_subs_epi16(x2[7], x2[6]); + x3[7] = _mm256_adds_epi16(x2[7], x2[6]); + + // stage 4 + __m256i x4[8]; + x4[0] = x3[0]; + x4[1] = x3[1]; + x4[2] = x3[2]; + x4[3] = x3[3]; + btf_16_w16_avx2(cospi_p56_p08, cospi_m08_p56, &x3[4], &x3[7], __rounding, + cos_bit); + x4[4] = x3[4]; + x4[7] = x3[7]; + btf_16_w16_avx2(cospi_p24_p40, cospi_m40_p24, &x3[5], &x3[6], __rounding, + cos_bit); + x4[5] = x3[5]; + x4[6] = x3[6]; + // stage 5 + output[0] = x4[0]; + output[1] = x4[4]; + output[2] = x4[2]; + output[3] = x4[6]; + output[4] = x4[1]; + output[5] = x4[5]; + output[6] = x4[3]; + output[7] = x4[7]; +} + +static INLINE void fadst8x8_new_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { + const int32_t *cospi = cospi_arr(cos_bit); + const __m256i __zero = _mm256_setzero_si256(); + const __m256i __rounding = _mm256_set1_epi32(1 << (cos_bit - 1)); + + __m256i cospi_p32_p32 = pair_set_w16_epi16(cospi[32], cospi[32]); + __m256i cospi_p32_m32 = pair_set_w16_epi16(cospi[32], -cospi[32]); + __m256i cospi_p16_p48 = pair_set_w16_epi16(cospi[16], cospi[48]); + __m256i cospi_p48_m16 = pair_set_w16_epi16(cospi[48], -cospi[16]); + __m256i cospi_m48_p16 = pair_set_w16_epi16(-cospi[48], cospi[16]); + __m256i cospi_p04_p60 = pair_set_w16_epi16(cospi[4], cospi[60]); + __m256i cospi_p60_m04 = pair_set_w16_epi16(cospi[60], -cospi[4]); + __m256i cospi_p20_p44 = pair_set_w16_epi16(cospi[20], cospi[44]); + __m256i cospi_p44_m20 = pair_set_w16_epi16(cospi[44], -cospi[20]); + __m256i cospi_p36_p28 = pair_set_w16_epi16(cospi[36], cospi[28]); + __m256i cospi_p28_m36 = pair_set_w16_epi16(cospi[28], -cospi[36]); + __m256i cospi_p52_p12 = pair_set_w16_epi16(cospi[52], cospi[12]); + __m256i cospi_p12_m52 = pair_set_w16_epi16(cospi[12], -cospi[52]); + + // stage 1 + __m256i x1[8]; + x1[0] = input[0]; + x1[1] = _mm256_subs_epi16(__zero, input[7]); + x1[2] = _mm256_subs_epi16(__zero, input[3]); + x1[3] = input[4]; + x1[4] = _mm256_subs_epi16(__zero, input[1]); + x1[5] = input[6]; + x1[6] = input[2]; + x1[7] = _mm256_subs_epi16(__zero, input[5]); + + // stage 2 + __m256i x2[8]; + x2[0] = x1[0]; + x2[1] = x1[1]; + btf_16_w16_avx2(cospi_p32_p32, cospi_p32_m32, &x1[2], &x1[3], __rounding, + cos_bit); + x2[2] = x1[2]; + x2[3] = x1[3]; + x2[4] = x1[4]; + x2[5] = x1[5]; + btf_16_w16_avx2(cospi_p32_p32, cospi_p32_m32, &x1[6], &x1[7], __rounding, + cos_bit); + x2[6] = x1[6]; + x2[7] = x1[7]; + + // stage 3 + __m256i x3[8]; + x3[0] = _mm256_adds_epi16(x2[0], x2[2]); + x3[2] = _mm256_subs_epi16(x2[0], x2[2]); + x3[1] = _mm256_adds_epi16(x2[1], x2[3]); + x3[3] = _mm256_subs_epi16(x2[1], x2[3]); + x3[4] = _mm256_adds_epi16(x2[4], x2[6]); + x3[6] = _mm256_subs_epi16(x2[4], x2[6]); + x3[5] = _mm256_adds_epi16(x2[5], x2[7]); + x3[7] = _mm256_subs_epi16(x2[5], x2[7]); + + // stage 4 + __m256i x4[8]; + x4[0] = x3[0]; + x4[1] = x3[1]; + x4[2] = x3[2]; + x4[3] = x3[3]; + btf_16_w16_avx2(cospi_p16_p48, cospi_p48_m16, &x3[4], &x3[5], __rounding, + cos_bit); + x4[4] = x3[4]; + x4[5] = x3[5]; + btf_16_w16_avx2(cospi_m48_p16, cospi_p16_p48, &x3[6], &x3[7], __rounding, + cos_bit); + x4[6] = x3[6]; + x4[7] = x3[7]; + + // stage 5 + __m256i x5[8]; + x5[0] = _mm256_adds_epi16(x4[0], x4[4]); + x5[4] = _mm256_subs_epi16(x4[0], x4[4]); + x5[1] = _mm256_adds_epi16(x4[1], x4[5]); + x5[5] = _mm256_subs_epi16(x4[1], x4[5]); + x5[2] = _mm256_adds_epi16(x4[2], x4[6]); + x5[6] = _mm256_subs_epi16(x4[2], x4[6]); + x5[3] = _mm256_adds_epi16(x4[3], x4[7]); + x5[7] = _mm256_subs_epi16(x4[3], x4[7]); + + // stage 6 + __m256i x6[8]; + btf_16_w16_avx2(cospi_p04_p60, cospi_p60_m04, &x5[0], &x5[1], __rounding, + cos_bit); + x6[0] = x5[0]; + x6[1] = x5[1]; + btf_16_w16_avx2(cospi_p20_p44, cospi_p44_m20, &x5[2], &x5[3], __rounding, + cos_bit); + x6[2] = x5[2]; + x6[3] = x5[3]; + btf_16_w16_avx2(cospi_p36_p28, cospi_p28_m36, &x5[4], &x5[5], __rounding, + cos_bit); + x6[4] = x5[4]; + x6[5] = x5[5]; + btf_16_w16_avx2(cospi_p52_p12, cospi_p12_m52, &x5[6], &x5[7], __rounding, + cos_bit); + x6[6] = x5[6]; + x6[7] = x5[7]; + + // stage 7 + output[0] = x6[1]; + output[1] = x6[6]; + output[2] = x6[3]; + output[3] = x6[4]; + output[4] = x6[5]; + output[5] = x6[2]; + output[6] = x6[7]; + output[7] = x6[0]; +} + +static INLINE void fidentity8x8_new_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { + (void)cos_bit; + + output[0] = _mm256_adds_epi16(input[0], input[0]); + output[1] = _mm256_adds_epi16(input[1], input[1]); + output[2] = _mm256_adds_epi16(input[2], input[2]); + output[3] = _mm256_adds_epi16(input[3], input[3]); + output[4] = _mm256_adds_epi16(input[4], input[4]); + output[5] = _mm256_adds_epi16(input[5], input[5]); + output[6] = _mm256_adds_epi16(input[6], input[6]); + output[7] = _mm256_adds_epi16(input[7], input[7]); +} + +static INLINE void fdct8x16_new_avx2(const __m128i *input, __m128i *output, + int8_t cos_bit) { + const int32_t *cospi = cospi_arr(cos_bit); + const __m256i __rounding_256 = _mm256_set1_epi32(1 << (cos_bit - 1)); + const __m128i __rounding = _mm_set1_epi32(1 << (cos_bit - 1)); + __m128i temp0, temp1, temp2, temp3; + __m256i in0, in1; + __m128i cospi_m32_p32 = pair_set_epi16(-cospi[32], cospi[32]); + __m128i cospi_p32_p32 = pair_set_epi16(cospi[32], cospi[32]); + __m128i cospi_p32_m32 = pair_set_epi16(cospi[32], -cospi[32]); + __m128i cospi_p48_p16 = pair_set_epi16(cospi[48], cospi[16]); + __m128i cospi_m16_p48 = pair_set_epi16(-cospi[16], cospi[48]); + __m128i cospi_m48_m16 = pair_set_epi16(-cospi[48], -cospi[16]); + __m128i cospi_p56_p08 = pair_set_epi16(cospi[56], cospi[8]); + __m128i cospi_m08_p56 = pair_set_epi16(-cospi[8], cospi[56]); + __m128i cospi_p24_p40 = pair_set_epi16(cospi[24], cospi[40]); + __m128i cospi_m40_p24 = pair_set_epi16(-cospi[40], cospi[24]); + __m128i cospi_p60_p04 = pair_set_epi16(cospi[60], cospi[4]); + __m128i cospi_m04_p60 = pair_set_epi16(-cospi[4], cospi[60]); + __m128i cospi_p28_p36 = pair_set_epi16(cospi[28], cospi[36]); + __m128i cospi_m36_p28 = pair_set_epi16(-cospi[36], cospi[28]); + __m128i cospi_p44_p20 = pair_set_epi16(cospi[44], cospi[20]); + __m128i cospi_m20_p44 = pair_set_epi16(-cospi[20], cospi[44]); + __m128i cospi_p12_p52 = pair_set_epi16(cospi[12], cospi[52]); + __m128i cospi_m52_p12 = pair_set_epi16(-cospi[52], cospi[12]); + + __m256i cospi_arr[12]; + + cospi_arr[0] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_m32_p32), + cospi_m32_p32, 0x1); + cospi_arr[1] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_p32), + cospi_p32_p32, 0x1); + cospi_arr[2] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_p32), + cospi_p48_p16, 0x1); + cospi_arr[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_m32), + cospi_m16_p48, 0x1); + cospi_arr[4] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_m16_p48), + cospi_m48_m16, 0x1); + cospi_arr[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p48_p16), + cospi_m16_p48, 0x1); + cospi_arr[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p56_p08), + cospi_p24_p40, 0x1); + cospi_arr[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_m08_p56), + cospi_m40_p24, 0x1); + cospi_arr[8] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p60_p04), + cospi_p28_p36, 0x1); + cospi_arr[9] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_m04_p60), + cospi_m36_p28, 0x1); + cospi_arr[10] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p44_p20), + cospi_p12_p52, 0x1); + cospi_arr[11] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_m20_p44), + cospi_m52_p12, 0x1); + + __m256i x[8]; + x[0] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[0]), input[1], 0x1); + x[1] = _mm256_insertf128_si256(_mm256_castsi128_si256(input[15]), input[14], + 0x1); + x[2] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[2]), input[3], 0x1); + x[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(input[13]), input[12], + 0x1); + x[4] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[5]), input[4], 0x1); + x[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(input[10]), input[11], + 0x1); + x[6] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[7]), input[6], 0x1); + x[7] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[8]), input[9], 0x1); + + // stage 1 + __m256i x1[8]; + x1[0] = _mm256_adds_epi16(x[0], x[1]); + x1[7] = _mm256_subs_epi16(x[0], x[1]); + x1[1] = _mm256_adds_epi16(x[2], x[3]); + x1[6] = _mm256_subs_epi16(x[2], x[3]); + x1[2] = _mm256_adds_epi16(x[4], x[5]); + x1[5] = _mm256_subs_epi16(x[4], x[5]); + x1[3] = _mm256_adds_epi16(x[6], x[7]); + x1[4] = _mm256_subs_epi16(x[6], x[7]); + + // stage 2 + __m256i x2[8]; + x2[0] = _mm256_adds_epi16(x1[0], x1[3]); + x2[7] = _mm256_subs_epi16(x1[0], x1[3]); + x2[1] = _mm256_adds_epi16(x1[1], x1[2]); + x2[6] = _mm256_subs_epi16(x1[1], x1[2]); + x2[2] = x1[4]; + x2[3] = x1[7]; + btf_16_avx2(&cospi_arr[0], &cospi_arr[1], &x1[5], &x1[6], &temp0, &temp1, + &temp2, &temp3, &__rounding_256, &cos_bit); + x2[4] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp0, 0x1); + x2[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp3), temp1, 0x1); + + // stage 3 + __m256i x3[8]; + x2[1] = _mm256_permute4x64_epi64(x2[1], 0x4e); + x3[0] = _mm256_adds_epi16(x2[0], x2[1]); + x3[1] = _mm256_subs_epi16(x2[0], x2[1]); + x3[2] = _mm256_blend_epi32(x2[7], x2[6], 0xf0); + btf_16_sse2(cospi_m32_p32, cospi_p32_p32, _mm256_castsi256_si128(x2[6]), + _mm256_extractf128_si256(x2[7], 0x01), temp0, temp1); + x3[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp1), temp0, 0x1); + x3[3] = _mm256_adds_epi16(x2[2], x2[4]); + x3[4] = _mm256_subs_epi16(x2[2], x2[4]); + x3[5] = _mm256_adds_epi16(x2[3], x2[5]); + x3[6] = _mm256_subs_epi16(x2[3], x2[5]); + + // stage 4 + __m256i x4[8]; + x4[0] = _mm256_blend_epi32(x3[0], x3[1], 0xf0); + x4[1] = _mm256_permute2f128_si256(x3[0], x3[1], 0x21); + btf_16_avx2(&cospi_arr[2], &cospi_arr[3], &x4[0], &x4[1], &output[0], + &output[8], &output[4], &output[12], &__rounding_256, &cos_bit); + x4[2] = _mm256_adds_epi16(x3[2], x3[7]); + x4[3] = _mm256_subs_epi16(x3[2], x3[7]); + x4[4] = _mm256_permute2f128_si256(x3[3], x3[4], 0x20); + x4[5] = _mm256_permute2f128_si256(x3[6], x3[5], 0x20); + in0 = _mm256_permute2f128_si256(x3[3], x3[4], 0x31); + in1 = _mm256_permute2f128_si256(x3[5], x3[6], 0x31); + btf_16_avx2(&cospi_arr[4], &cospi_arr[5], &in0, &in1, &temp0, &temp1, &temp2, + &temp3, &__rounding_256, &cos_bit); + + x4[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp2, 0x1); + x4[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp3), temp1, 0x1); + + // stage 5 + __m256i x5[4]; + in0 = _mm256_permute2f128_si256(x4[2], x4[3], 0x31); + in1 = _mm256_permute2f128_si256(x4[2], x4[3], 0x20); + btf_16_avx2(&cospi_arr[6], &cospi_arr[7], &in0, &in1, &output[2], &output[14], + &output[10], &output[6], &__rounding_256, &cos_bit); + x5[0] = _mm256_adds_epi16(x4[4], x4[6]); + x5[1] = _mm256_subs_epi16(x4[4], x4[6]); + x5[2] = _mm256_adds_epi16(x4[5], x4[7]); + x5[3] = _mm256_subs_epi16(x4[5], x4[7]); + + // stage 6 + in0 = _mm256_permute2f128_si256(x5[0], x5[1], 0x20); + in1 = _mm256_permute2f128_si256(x5[2], x5[3], 0x31); + btf_16_avx2(&cospi_arr[8], &cospi_arr[9], &in0, &in1, &output[1], &output[15], + &output[9], &output[7], &__rounding_256, &cos_bit); + in0 = _mm256_permute2f128_si256(x5[1], x5[0], 0x31); + in1 = _mm256_permute2f128_si256(x5[3], x5[2], 0x20); + btf_16_avx2(&cospi_arr[10], &cospi_arr[11], &in0, &in1, &output[5], + &output[11], &output[13], &output[3], &__rounding_256, &cos_bit); +} + +static INLINE void fadst8x16_new_avx2(const __m128i *input, __m128i *output, + int8_t cos_bit) { + const int32_t *cospi = cospi_arr(cos_bit); + const __m256i __zero = _mm256_setzero_si256(); + const __m256i __rounding_256 = _mm256_set1_epi32(1 << (cos_bit - 1)); + __m256i in0, in1; + __m128i temp0, temp1, temp2, temp3; + + __m128i cospi_p32_p32 = pair_set_epi16(cospi[32], cospi[32]); + __m128i cospi_p32_m32 = pair_set_epi16(cospi[32], -cospi[32]); + __m128i cospi_p16_p48 = pair_set_epi16(cospi[16], cospi[48]); + __m128i cospi_p48_m16 = pair_set_epi16(cospi[48], -cospi[16]); + __m128i cospi_m48_p16 = pair_set_epi16(-cospi[48], cospi[16]); + __m128i cospi_p08_p56 = pair_set_epi16(cospi[8], cospi[56]); + __m128i cospi_p56_m08 = pair_set_epi16(cospi[56], -cospi[8]); + __m128i cospi_p40_p24 = pair_set_epi16(cospi[40], cospi[24]); + __m128i cospi_p24_m40 = pair_set_epi16(cospi[24], -cospi[40]); + __m128i cospi_m56_p08 = pair_set_epi16(-cospi[56], cospi[8]); + __m128i cospi_m24_p40 = pair_set_epi16(-cospi[24], cospi[40]); + __m128i cospi_p02_p62 = pair_set_epi16(cospi[2], cospi[62]); + __m128i cospi_p62_m02 = pair_set_epi16(cospi[62], -cospi[2]); + __m128i cospi_p10_p54 = pair_set_epi16(cospi[10], cospi[54]); + __m128i cospi_p54_m10 = pair_set_epi16(cospi[54], -cospi[10]); + __m128i cospi_p18_p46 = pair_set_epi16(cospi[18], cospi[46]); + __m128i cospi_p46_m18 = pair_set_epi16(cospi[46], -cospi[18]); + __m128i cospi_p26_p38 = pair_set_epi16(cospi[26], cospi[38]); + __m128i cospi_p38_m26 = pair_set_epi16(cospi[38], -cospi[26]); + __m128i cospi_p34_p30 = pair_set_epi16(cospi[34], cospi[30]); + __m128i cospi_p30_m34 = pair_set_epi16(cospi[30], -cospi[34]); + __m128i cospi_p42_p22 = pair_set_epi16(cospi[42], cospi[22]); + __m128i cospi_p22_m42 = pair_set_epi16(cospi[22], -cospi[42]); + __m128i cospi_p50_p14 = pair_set_epi16(cospi[50], cospi[14]); + __m128i cospi_p14_m50 = pair_set_epi16(cospi[14], -cospi[50]); + __m128i cospi_p58_p06 = pair_set_epi16(cospi[58], cospi[6]); + __m128i cospi_p06_m58 = pair_set_epi16(cospi[6], -cospi[58]); + + __m256i cospi_arr[20]; + + cospi_arr[0] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_p32), + cospi_p32_p32, 0x1); + cospi_arr[1] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_m32), + cospi_p32_m32, 0x1); + cospi_arr[2] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_p32), + cospi_p32_p32, 0x1); + cospi_arr[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p32_m32), + cospi_p32_m32, 0x1); + cospi_arr[4] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p16_p48), + cospi_m48_p16, 0x1); + cospi_arr[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p48_m16), + cospi_p16_p48, 0x1); + cospi_arr[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p16_p48), + cospi_m48_p16, 0x1); + cospi_arr[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p48_m16), + cospi_p16_p48, 0x1); + cospi_arr[8] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p08_p56), + cospi_p40_p24, 0x1); + cospi_arr[9] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p56_m08), + cospi_p24_m40, 0x1); + cospi_arr[10] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_m56_p08), + cospi_m24_p40, 0x1); + cospi_arr[11] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p08_p56), + cospi_p40_p24, 0x1); + cospi_arr[12] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p02_p62), + cospi_p10_p54, 0x1); + cospi_arr[13] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p62_m02), + cospi_p54_m10, 0x1); + cospi_arr[14] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p18_p46), + cospi_p26_p38, 0x1); + cospi_arr[15] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p46_m18), + cospi_p38_m26, 0x1); + cospi_arr[16] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p34_p30), + cospi_p42_p22, 0x1); + cospi_arr[17] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p30_m34), + cospi_p22_m42, 0x1); + cospi_arr[18] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p50_p14), + cospi_p58_p06, 0x1); + cospi_arr[19] = _mm256_insertf128_si256(_mm256_castsi128_si256(cospi_p14_m50), + cospi_p06_m58, 0x1); + + __m256i x[8]; + x[0] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[0]), input[4], 0x1); + x[1] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[2]), input[6], 0x1); + x[2] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[8]), input[12], 0x1); + x[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(input[10]), input[14], + 0x1); + x[4] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[1]), input[9], 0x1); + x[5] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[3]), input[11], 0x1); + x[6] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[5]), input[13], 0x1); + x[7] = + _mm256_insertf128_si256(_mm256_castsi128_si256(input[7]), input[15], 0x1); + + // stage 1 + __m256i x1[8]; + x1[0] = x[0]; + x1[1] = _mm256_subs_epi16(__zero, x[7]); + x1[2] = x[2]; + x1[3] = _mm256_subs_epi16(__zero, x[5]); + x1[4] = _mm256_subs_epi16(__zero, x[4]); + x1[5] = x[3]; + x1[6] = _mm256_subs_epi16(__zero, x[6]); + x1[7] = x[1]; + + // stage 2 + __m256i x2[8]; + x2[0] = _mm256_blend_epi32(x1[0], x1[1], 0xf0); + x2[3] = _mm256_blend_epi32(x1[3], x1[2], 0xf0); + x2[4] = _mm256_blend_epi32(x1[4], x1[5], 0xf0); + x2[7] = _mm256_blend_epi32(x1[7], x1[6], 0xf0); + in0 = _mm256_blend_epi32(x1[1], x1[0], 0xf0); + in1 = _mm256_blend_epi32(x1[2], x1[3], 0xf0); + btf_16_avx2(&cospi_arr[0], &cospi_arr[1], &in0, &in1, &temp0, &temp1, &temp2, + &temp3, &__rounding_256, &cos_bit); + x2[1] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp1, 0x1); + x2[2] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp3, 0x1); + in0 = _mm256_permute2f128_si256(x1[7], x1[6], 0x21); + in1 = _mm256_permute2f128_si256(x1[4], x1[5], 0x21); + btf_16_avx2(&cospi_arr[2], &cospi_arr[3], &in0, &in1, &temp0, &temp1, &temp2, + &temp3, &__rounding_256, &cos_bit); + x2[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp1, 0x1); + x2[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp3, 0x1); + + // stage 3 + __m256i x3[8]; + x3[0] = _mm256_adds_epi16(x2[0], x2[1]); + x3[1] = _mm256_subs_epi16(x2[0], x2[1]); + x3[2] = _mm256_adds_epi16(x2[3], x2[2]); + x3[3] = _mm256_subs_epi16(x2[3], x2[2]); + x3[4] = _mm256_adds_epi16(x2[4], x2[5]); + x3[5] = _mm256_subs_epi16(x2[4], x2[5]); + x3[6] = _mm256_adds_epi16(x2[7], x2[6]); + x3[7] = _mm256_subs_epi16(x2[7], x2[6]); + + // stage 4 + __m256i x4[8]; + x4[0] = x3[0]; + x4[1] = x3[1]; + x4[4] = x3[4]; + x4[5] = x3[5]; + in0 = _mm256_permute2f128_si256(x3[2], x3[3], 0x20); + in1 = _mm256_permute2f128_si256(x3[2], x3[3], 0x31); + btf_16_avx2(&cospi_arr[4], &cospi_arr[5], &in0, &in1, &temp0, &temp1, &temp2, + &temp3, &__rounding_256, &cos_bit); + x4[2] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp1, 0x1); + x4[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp3, 0x1); + in0 = _mm256_permute2f128_si256(x3[6], x3[7], 0x20); + in1 = _mm256_permute2f128_si256(x3[6], x3[7], 0x31); + btf_16_avx2(&cospi_arr[6], &cospi_arr[7], &in0, &in1, &temp0, &temp1, &temp2, + &temp3, &__rounding_256, &cos_bit); + x4[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp1, 0x1); + x4[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp3, 0x1); + + // stage 5 + __m256i x5[8]; + x5[0] = _mm256_adds_epi16(x4[0], x4[2]); + x5[1] = _mm256_subs_epi16(x4[0], x4[2]); + x5[2] = _mm256_adds_epi16(x4[1], x4[3]); + x5[3] = _mm256_subs_epi16(x4[1], x4[3]); + x5[4] = _mm256_adds_epi16(x4[4], x4[6]); + x5[5] = _mm256_subs_epi16(x4[4], x4[6]); + x5[6] = _mm256_adds_epi16(x4[5], x4[7]); + x5[7] = _mm256_subs_epi16(x4[5], x4[7]); + + // stage 6 + __m256i x6[8]; + x6[0] = x5[0]; + x6[1] = x5[2]; + x6[2] = x5[1]; + x6[3] = x5[3]; + in0 = _mm256_permute2f128_si256(x5[4], x5[6], 0x20); + in1 = _mm256_permute2f128_si256(x5[4], x5[6], 0x31); + btf_16_avx2(&cospi_arr[8], &cospi_arr[9], &in0, &in1, &temp0, &temp1, &temp2, + &temp3, &__rounding_256, &cos_bit); + x6[4] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp1, 0x1); + x6[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp3, 0x1); + in0 = _mm256_permute2f128_si256(x5[5], x5[7], 0x20); + in1 = _mm256_permute2f128_si256(x5[5], x5[7], 0x31); + btf_16_avx2(&cospi_arr[10], &cospi_arr[11], &in0, &in1, &temp0, &temp1, + &temp2, &temp3, &__rounding_256, &cos_bit); + x6[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp0), temp1, 0x1); + x6[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(temp2), temp3, 0x1); + + // stage 7 + __m256i x7[8]; + x7[0] = _mm256_adds_epi16(x6[0], x6[4]); + x7[1] = _mm256_subs_epi16(x6[0], x6[4]); + x7[2] = _mm256_adds_epi16(x6[1], x6[5]); + x7[3] = _mm256_subs_epi16(x6[1], x6[5]); + x7[4] = _mm256_adds_epi16(x6[2], x6[6]); + x7[5] = _mm256_subs_epi16(x6[2], x6[6]); + x7[6] = _mm256_adds_epi16(x6[3], x6[7]); + x7[7] = _mm256_subs_epi16(x6[3], x6[7]); + + // stage 8 + in0 = _mm256_permute2f128_si256(x7[0], x7[2], 0x20); + in1 = _mm256_permute2f128_si256(x7[0], x7[2], 0x31); + btf_16_avx2(&cospi_arr[12], &cospi_arr[13], &in0, &in1, &output[15], + &output[0], &output[13], &output[2], &__rounding_256, &cos_bit); + in0 = _mm256_permute2f128_si256(x7[4], x7[6], 0x20); + in1 = _mm256_permute2f128_si256(x7[4], x7[6], 0x31); + btf_16_avx2(&cospi_arr[14], &cospi_arr[15], &in0, &in1, &output[11], + &output[4], &output[9], &output[6], &__rounding_256, &cos_bit); + in0 = _mm256_permute2f128_si256(x7[1], x7[3], 0x20); + in1 = _mm256_permute2f128_si256(x7[1], x7[3], 0x31); + btf_16_avx2(&cospi_arr[16], &cospi_arr[17], &in0, &in1, &output[7], + &output[8], &output[5], &output[10], &__rounding_256, &cos_bit); + in0 = _mm256_permute2f128_si256(x7[5], x7[7], 0x20); + in1 = _mm256_permute2f128_si256(x7[5], x7[7], 0x31); + btf_16_avx2(&cospi_arr[18], &cospi_arr[19], &in0, &in1, &output[3], + &output[12], &output[1], &output[14], &__rounding_256, &cos_bit); +} + +static INLINE void fidentity8x16_new_avx2(const __m128i *input, __m128i *output, + int8_t cos_bit) { + (void)cos_bit; + const __m256i one = _mm256_set1_epi16(1); + __m256i temp; + for (int i = 0; i < 16; i += 2) { + temp = _mm256_insertf128_si256(_mm256_castsi128_si256(input[i]), + input[i + 1], 0x1); + const __m256i a_lo = _mm256_unpacklo_epi16(temp, one); + const __m256i a_hi = _mm256_unpackhi_epi16(temp, one); + const __m256i b_lo = scale_round_avx2(a_lo, 2 * NewSqrt2); + const __m256i b_hi = scale_round_avx2(a_hi, 2 * NewSqrt2); + temp = _mm256_packs_epi32(b_lo, b_hi); + output[i] = _mm256_castsi256_si128(temp); + output[i + 1] = _mm256_extractf128_si256(temp, 0x1); + } +} + +static const transform_1d_avx2 row_txfm8x16_arr[TX_TYPES] = { + fdct8x8_new_avx2, // DCT_DCT + fdct8x8_new_avx2, // ADST_DCT + fadst8x8_new_avx2, // DCT_ADST + fadst8x8_new_avx2, // ADST_ADST + fdct8x8_new_avx2, // FLIPADST_DCT + fadst8x8_new_avx2, // DCT_FLIPADST + fadst8x8_new_avx2, // FLIPADST_FLIPADST + fadst8x8_new_avx2, // ADST_FLIPADST + fadst8x8_new_avx2, // FLIPADST_ADST + fidentity8x8_new_avx2, // IDTX + fidentity8x8_new_avx2, // V_DCT + fdct8x8_new_avx2, // H_DCT + fidentity8x8_new_avx2, // V_ADST + fadst8x8_new_avx2, // H_ADST + fidentity8x8_new_avx2, // V_FLIPADST + fadst8x8_new_avx2 // H_FLIPADST +}; + +static const transform_1d_sse2 col_txfm8x16_arr[TX_TYPES] = { + fdct8x16_new_avx2, // DCT_DCT + fadst8x16_new_avx2, // ADST_DCT + fdct8x16_new_avx2, // DCT_ADST + fadst8x16_new_avx2, // ADST_ADST + fadst8x16_new_avx2, // FLIPADST_DCT + fdct8x16_new_avx2, // DCT_FLIPADST + fadst8x16_new_avx2, // FLIPADST_FLIPADST + fadst8x16_new_avx2, // ADST_FLIPADST + fadst8x16_new_avx2, // FLIPADST_ADST + fidentity8x16_new_avx2, // IDTX + fdct8x16_new_avx2, // V_DCT + fidentity8x16_new_avx2, // H_DCT + fadst8x16_new_avx2, // V_ADST + fidentity8x16_new_avx2, // H_ADST + fadst8x16_new_avx2, // V_FLIPADST + fidentity8x16_new_avx2 // H_FLIPADST +}; + +static const transform_1d_avx2 col_txfm16x8_arr[TX_TYPES] = { + fdct8x8_new_avx2, // DCT_DCT + fadst8x8_new_avx2, // ADST_DCT + fdct8x8_new_avx2, // DCT_ADST + fadst8x8_new_avx2, // ADST_ADST + fadst8x8_new_avx2, // FLIPADST_DCT + fdct8x8_new_avx2, // DCT_FLIPADST + fadst8x8_new_avx2, // FLIPADST_FLIPADST + fadst8x8_new_avx2, // ADST_FLIPADST + fadst8x8_new_avx2, // FLIPADST_ADST + fidentity8x8_new_avx2, // IDTX + fdct8x8_new_avx2, // V_DCT + fidentity8x8_new_avx2, // H_DCT + fadst8x8_new_avx2, // V_ADST + fidentity8x8_new_avx2, // H_ADST + fadst8x8_new_avx2, // V_FLIPADST + fidentity8x8_new_avx2, // H_FLIPADST +}; + +static const transform_1d_sse2 row_txfm16x8_arr[TX_TYPES] = { + fdct8x16_new_avx2, // DCT_DCT + fdct8x16_new_avx2, // ADST_DCT + fadst8x16_new_avx2, // DCT_ADST + fadst8x16_new_avx2, // ADST_ADST + fdct8x16_new_avx2, // FLIPADST_DCT + fadst8x16_new_avx2, // DCT_FLIPADST + fadst8x16_new_avx2, // FLIPADST_FLIPADST + fadst8x16_new_avx2, // ADST_FLIPADST + fadst8x16_new_avx2, // FLIPADST_ADST + fidentity8x16_new_avx2, // IDTX + fidentity8x16_new_avx2, // V_DCT + fdct8x16_new_avx2, // H_DCT + fidentity8x16_new_avx2, // V_ADST + fadst8x16_new_avx2, // H_ADST + fidentity8x16_new_avx2, // V_FLIPADST + fadst8x16_new_avx2 // H_FLIPADST +}; + +static void lowbd_fwd_txfm2d_8x16_avx2(const int16_t *input, int32_t *output, + int stride, TX_TYPE tx_type, int bd) { + (void)bd; + __m128i buf0[16], buf1[16]; + __m256i buf2[8]; + const int8_t *shift = fwd_txfm_shift_ls[TX_8X16]; + const int txw_idx = get_txw_idx(TX_8X16); + const int txh_idx = get_txh_idx(TX_8X16); + const int cos_bit_col = fwd_cos_bit_col[txw_idx][txh_idx]; + const int cos_bit_row = fwd_cos_bit_row[txw_idx][txh_idx]; + const int width = 8; + const int height = 16; + const transform_1d_sse2 col_txfm = col_txfm8x16_arr[tx_type]; + const transform_1d_avx2 row_txfm = row_txfm8x16_arr[tx_type]; + int ud_flip, lr_flip; + + get_flip_cfg(tx_type, &ud_flip, &lr_flip); + if (ud_flip) { + load_buffer_16bit_to_16bit_flip(input, stride, buf0, height); + } else { + load_buffer_16bit_to_16bit(input, stride, buf0, height); + } + round_shift_16bit(buf0, height, shift[0]); + col_txfm(buf0, buf0, cos_bit_col); + round_shift_16bit(buf0, height, shift[1]); + transpose_16bit_8x8(buf0, buf1); + transpose_16bit_8x8(buf0 + 8, buf1 + 8); + + __m128i *bufl, *bufu; + if (lr_flip) { + bufl = buf0; + bufu = buf0 + 8; + flip_buf_sse2(buf1 + width * 0, bufl, width); + flip_buf_sse2(buf1 + width * 1, bufu, width); + } else { + bufl = buf1 + width * 0; + bufu = buf1 + width * 1; + } + pack_reg(bufl, bufu, buf2); + row_txfm(buf2, buf2, cos_bit_row); + round_shift_16bit_w16_avx2(buf2, width, shift[2]); + transpose_16bit_16x8_avx2(buf2, buf2); + store_rect_buffer_16bit_to_32bit_w8_avx2(buf2, output, width, 8); +} + +static void lowbd_fwd_txfm2d_16x8_avx2(const int16_t *input, int32_t *output, + int stride, TX_TYPE tx_type, int bd) { + (void)bd; + __m128i buf0[16], buf1[16]; + __m256i buf2[8]; + const int8_t *shift = fwd_txfm_shift_ls[TX_16X8]; + const int txw_idx = get_txw_idx(TX_16X8); + const int txh_idx = get_txh_idx(TX_16X8); + const int cos_bit_col = fwd_cos_bit_col[txw_idx][txh_idx]; + const int cos_bit_row = fwd_cos_bit_row[txw_idx][txh_idx]; + const int width = 16; + const int height = 8; + const transform_1d_avx2 col_txfm = col_txfm16x8_arr[tx_type]; + const transform_1d_sse2 row_txfm = row_txfm16x8_arr[tx_type]; + __m128i *buf; + int ud_flip, lr_flip; + + get_flip_cfg(tx_type, &ud_flip, &lr_flip); + + if (ud_flip) { + load_buffer_16bit_to_16bit_flip(input + 8 * 0, stride, buf0, height); + load_buffer_16bit_to_16bit_flip(input + 8 * 1, stride, &buf0[8], height); + } else { + load_buffer_16bit_to_16bit(input + 8 * 0, stride, buf0, height); + load_buffer_16bit_to_16bit(input + 8 * 1, stride, &buf0[8], height); + } + pack_reg(buf0, &buf0[8], buf2); + round_shift_16bit_w16_avx2(buf2, height, shift[0]); + col_txfm(buf2, buf2, cos_bit_col); + round_shift_16bit_w16_avx2(buf2, height, shift[1]); + transpose_16bit_16x8_avx2(buf2, buf2); + extract_reg(buf2, buf1); + + if (lr_flip) { + buf = buf0; + flip_buf_sse2(buf1, buf, width); + } else { + buf = buf1; + } + row_txfm(buf, buf, cos_bit_row); + round_shift_16bit(buf, width, shift[2]); + transpose_16bit_8x8(buf, buf); + store_rect_buffer_16bit_to_32bit_w8(buf, output, width, height); + transpose_16bit_8x8(buf + 8, buf + 8); + store_rect_buffer_16bit_to_32bit_w8(buf + 8, output + 8, width, height); +} + static FwdTxfm2dFunc fwd_txfm2d_func_ls[TX_SIZES_ALL] = { av1_lowbd_fwd_txfm2d_4x4_sse2, // 4x4 transform av1_lowbd_fwd_txfm2d_8x8_sse2, // 8x8 transform @@ -2005,8 +2787,8 @@ static FwdTxfm2dFunc fwd_txfm2d_func_ls[TX_SIZES_ALL] = { lowbd_fwd_txfm2d_64x64_avx2, // 64x64 transform av1_lowbd_fwd_txfm2d_4x8_sse2, // 4x8 transform av1_lowbd_fwd_txfm2d_8x4_sse2, // 8x4 transform - av1_lowbd_fwd_txfm2d_8x16_sse2, // 8x16 transform - av1_lowbd_fwd_txfm2d_16x8_sse2, // 16x8 transform + lowbd_fwd_txfm2d_8x16_avx2, // 8x16 transform + lowbd_fwd_txfm2d_16x8_avx2, // 16x8 transform lowbd_fwd_txfm2d_16x32_avx2, // 16x32 transform lowbd_fwd_txfm2d_32x16_avx2, // 32x16 transform lowbd_fwd_txfm2d_32x64_avx2, // 32x64 transform diff --git a/third_party/aom/av1/encoder/x86/corner_match_avx2.c b/third_party/aom/av1/encoder/x86/corner_match_avx2.c index 3351d0af19..7a3b99970e 100644 --- a/third_party/aom/av1/encoder/x86/corner_match_avx2.c +++ b/third_party/aom/av1/encoder/x86/corner_match_avx2.c @@ -9,10 +9,7 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ -#include -#include #include -#include #include #include "config/av1_rtcd.h" diff --git a/third_party/aom/av1/encoder/x86/highbd_block_error_intrin_avx2.c b/third_party/aom/av1/encoder/x86/highbd_block_error_intrin_avx2.c new file mode 100644 index 0000000000..719734c438 --- /dev/null +++ b/third_party/aom/av1/encoder/x86/highbd_block_error_intrin_avx2.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 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 +#include +#include "aom/aom_integer.h" +#include "av1/common/common.h" + +int64_t av1_highbd_block_error_avx2(tran_low_t *coeff, tran_low_t *dqcoeff, + intptr_t block_size, int64_t *ssz, + int bps) { + int i; + int64_t temp1[8]; + int64_t error = 0, sqcoeff = 0; + const int shift = 2 * (bps - 8); + const int rounding = shift > 0 ? 1 << (shift - 1) : 0; + + for (i = 0; i < block_size; i += 16) { + __m256i mm256_coeff = _mm256_loadu_si256((__m256i *)(coeff + i)); + __m256i mm256_coeff2 = _mm256_loadu_si256((__m256i *)(coeff + i + 8)); + __m256i mm256_dqcoeff = _mm256_loadu_si256((__m256i *)(dqcoeff + i)); + __m256i mm256_dqcoeff2 = _mm256_loadu_si256((__m256i *)(dqcoeff + i + 8)); + + __m256i diff1 = _mm256_sub_epi32(mm256_coeff, mm256_dqcoeff); + __m256i diff2 = _mm256_sub_epi32(mm256_coeff2, mm256_dqcoeff2); + __m256i diff1h = _mm256_srli_epi64(diff1, 32); + __m256i diff2h = _mm256_srli_epi64(diff2, 32); + __m256i res = _mm256_mul_epi32(diff1, diff1); + __m256i res1 = _mm256_mul_epi32(diff1h, diff1h); + __m256i res2 = _mm256_mul_epi32(diff2, diff2); + __m256i res3 = _mm256_mul_epi32(diff2h, diff2h); + __m256i res_diff = _mm256_add_epi64(_mm256_add_epi64(res, res1), + _mm256_add_epi64(res2, res3)); + __m256i mm256_coeffh = _mm256_srli_epi64(mm256_coeff, 32); + __m256i mm256_coeffh2 = _mm256_srli_epi64(mm256_coeff2, 32); + res = _mm256_mul_epi32(mm256_coeff, mm256_coeff); + res1 = _mm256_mul_epi32(mm256_coeffh, mm256_coeffh); + res2 = _mm256_mul_epi32(mm256_coeff2, mm256_coeff2); + res3 = _mm256_mul_epi32(mm256_coeffh2, mm256_coeffh2); + __m256i res_sqcoeff = _mm256_add_epi64(_mm256_add_epi64(res, res1), + _mm256_add_epi64(res2, res3)); + _mm256_storeu_si256((__m256i *)temp1, res_diff); + _mm256_storeu_si256((__m256i *)temp1 + 1, res_sqcoeff); + + error += temp1[0] + temp1[1] + temp1[2] + temp1[3]; + sqcoeff += temp1[4] + temp1[5] + temp1[6] + temp1[7]; + } + assert(error >= 0 && sqcoeff >= 0); + error = (error + rounding) >> shift; + sqcoeff = (sqcoeff + rounding) >> shift; + + *ssz = sqcoeff; + return error; +} diff --git a/third_party/aom/av1/encoder/x86/highbd_temporal_filter_sse4.c b/third_party/aom/av1/encoder/x86/highbd_temporal_filter_sse4.c new file mode 100644 index 0000000000..f199b0f9b7 --- /dev/null +++ b/third_party/aom/av1/encoder/x86/highbd_temporal_filter_sse4.c @@ -0,0 +1,954 @@ +/* + * Copyright (c) 2019, 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 +#include + +#include "config/av1_rtcd.h" +#include "aom/aom_integer.h" +#include "av1/encoder/encoder.h" +#include "av1/encoder/temporal_filter.h" +#include "av1/encoder/x86/temporal_filter_constants.h" + +// Compute (a-b)**2 for 8 pixels with size 16-bit +static INLINE void highbd_store_dist_8(const uint16_t *a, const uint16_t *b, + uint32_t *dst) { + const __m128i zero = _mm_setzero_si128(); + const __m128i a_reg = _mm_loadu_si128((const __m128i *)a); + const __m128i b_reg = _mm_loadu_si128((const __m128i *)b); + + const __m128i a_first = _mm_cvtepu16_epi32(a_reg); + const __m128i a_second = _mm_unpackhi_epi16(a_reg, zero); + const __m128i b_first = _mm_cvtepu16_epi32(b_reg); + const __m128i b_second = _mm_unpackhi_epi16(b_reg, zero); + + __m128i dist_first, dist_second; + + dist_first = _mm_sub_epi32(a_first, b_first); + dist_second = _mm_sub_epi32(a_second, b_second); + dist_first = _mm_mullo_epi32(dist_first, dist_first); + dist_second = _mm_mullo_epi32(dist_second, dist_second); + + _mm_storeu_si128((__m128i *)dst, dist_first); + _mm_storeu_si128((__m128i *)(dst + 4), dist_second); +} + +// Sum up three neighboring distortions for the pixels +static INLINE void highbd_get_sum_4(const uint32_t *dist, __m128i *sum) { + __m128i dist_reg, dist_left, dist_right; + + dist_reg = _mm_loadu_si128((const __m128i *)dist); + dist_left = _mm_loadu_si128((const __m128i *)(dist - 1)); + dist_right = _mm_loadu_si128((const __m128i *)(dist + 1)); + + *sum = _mm_add_epi32(dist_reg, dist_left); + *sum = _mm_add_epi32(*sum, dist_right); +} + +static INLINE void highbd_get_sum_8(const uint32_t *dist, __m128i *sum_first, + __m128i *sum_second) { + highbd_get_sum_4(dist, sum_first); + highbd_get_sum_4(dist + 4, sum_second); +} + +// Average the value based on the number of values summed (9 for pixels away +// from the border, 4 for pixels in corners, and 6 for other edge values, plus +// however many values from y/uv plane are). +// +// Add in the rounding factor and shift, clamp to 16, invert and shift. Multiply +// by weight. +static INLINE void highbd_average_4(__m128i *output, const __m128i *sum, + const __m128i *mul_constants, + const int strength, const int rounding, + const int weight) { + // _mm_srl_epi16 uses the lower 64 bit value for the shift. + const __m128i strength_u128 = _mm_set_epi32(0, 0, 0, strength); + const __m128i rounding_u32 = _mm_set1_epi32(rounding); + const __m128i weight_u32 = _mm_set1_epi32(weight); + const __m128i sixteen = _mm_set1_epi32(16); + const __m128i zero = _mm_setzero_si128(); + + // modifier * 3 / index; + const __m128i sum_lo = _mm_unpacklo_epi32(*sum, zero); + const __m128i sum_hi = _mm_unpackhi_epi32(*sum, zero); + const __m128i const_lo = _mm_unpacklo_epi32(*mul_constants, zero); + const __m128i const_hi = _mm_unpackhi_epi32(*mul_constants, zero); + + const __m128i mul_lo = _mm_mul_epu32(sum_lo, const_lo); + const __m128i mul_lo_div = _mm_srli_epi64(mul_lo, 32); + const __m128i mul_hi = _mm_mul_epu32(sum_hi, const_hi); + const __m128i mul_hi_div = _mm_srli_epi64(mul_hi, 32); + + // Now we have + // mul_lo: 00 a1 00 a0 + // mul_hi: 00 a3 00 a2 + // Unpack as 64 bit words to get even and odd elements + // unpack_lo: 00 a2 00 a0 + // unpack_hi: 00 a3 00 a1 + // Then we can shift and OR the results to get everything in 32-bits + const __m128i mul_even = _mm_unpacklo_epi64(mul_lo_div, mul_hi_div); + const __m128i mul_odd = _mm_unpackhi_epi64(mul_lo_div, mul_hi_div); + const __m128i mul_odd_shift = _mm_slli_si128(mul_odd, 4); + const __m128i mul = _mm_or_si128(mul_even, mul_odd_shift); + + // Round + *output = _mm_add_epi32(mul, rounding_u32); + *output = _mm_srl_epi32(*output, strength_u128); + + // Multiply with the weight + *output = _mm_min_epu32(*output, sixteen); + *output = _mm_sub_epi32(sixteen, *output); + *output = _mm_mullo_epi32(*output, weight_u32); +} + +static INLINE void highbd_average_8(__m128i *output_0, __m128i *output_1, + const __m128i *sum_0_u32, + const __m128i *sum_1_u32, + const __m128i *mul_constants_0, + const __m128i *mul_constants_1, + const int strength, const int rounding, + const int weight) { + highbd_average_4(output_0, sum_0_u32, mul_constants_0, strength, rounding, + weight); + highbd_average_4(output_1, sum_1_u32, mul_constants_1, strength, rounding, + weight); +} + +// Add 'sum_u32' to 'count'. Multiply by 'pred' and add to 'accumulator.' +static INLINE void highbd_accumulate_and_store_8(const __m128i sum_first_u32, + const __m128i sum_second_u32, + const uint16_t *pred, + uint16_t *count, + uint32_t *accumulator) { + // Cast down to 16-bit ints + const __m128i sum_u16 = _mm_packus_epi32(sum_first_u32, sum_second_u32); + const __m128i zero = _mm_setzero_si128(); + + __m128i pred_u16 = _mm_loadu_si128((const __m128i *)pred); + __m128i count_u16 = _mm_loadu_si128((const __m128i *)count); + + __m128i pred_0_u32, pred_1_u32; + __m128i accum_0_u32, accum_1_u32; + + count_u16 = _mm_adds_epu16(count_u16, sum_u16); + _mm_storeu_si128((__m128i *)count, count_u16); + + pred_u16 = _mm_mullo_epi16(sum_u16, pred_u16); + + pred_0_u32 = _mm_cvtepu16_epi32(pred_u16); + pred_1_u32 = _mm_unpackhi_epi16(pred_u16, zero); + + accum_0_u32 = _mm_loadu_si128((const __m128i *)accumulator); + accum_1_u32 = _mm_loadu_si128((const __m128i *)(accumulator + 4)); + + accum_0_u32 = _mm_add_epi32(pred_0_u32, accum_0_u32); + accum_1_u32 = _mm_add_epi32(pred_1_u32, accum_1_u32); + + _mm_storeu_si128((__m128i *)accumulator, accum_0_u32); + _mm_storeu_si128((__m128i *)(accumulator + 4), accum_1_u32); +} + +static INLINE void highbd_read_dist_4(const uint32_t *dist, __m128i *dist_reg) { + *dist_reg = _mm_loadu_si128((const __m128i *)dist); +} + +static INLINE void highbd_read_dist_8(const uint32_t *dist, __m128i *reg_first, + __m128i *reg_second) { + highbd_read_dist_4(dist, reg_first); + highbd_read_dist_4(dist + 4, reg_second); +} + +static INLINE void highbd_read_chroma_dist_row_8( + int ss_x, const uint32_t *u_dist, const uint32_t *v_dist, __m128i *u_first, + __m128i *u_second, __m128i *v_first, __m128i *v_second) { + if (!ss_x) { + // If there is no chroma subsampling in the horizontal direction, then we + // need to load 8 entries from chroma. + highbd_read_dist_8(u_dist, u_first, u_second); + highbd_read_dist_8(v_dist, v_first, v_second); + } else { // ss_x == 1 + // Otherwise, we only need to load 8 entries + __m128i u_reg, v_reg; + + highbd_read_dist_4(u_dist, &u_reg); + + *u_first = _mm_unpacklo_epi32(u_reg, u_reg); + *u_second = _mm_unpackhi_epi32(u_reg, u_reg); + + highbd_read_dist_4(v_dist, &v_reg); + + *v_first = _mm_unpacklo_epi32(v_reg, v_reg); + *v_second = _mm_unpackhi_epi32(v_reg, v_reg); + } +} + +static void av1_highbd_apply_temporal_filter_luma_8( + const uint16_t *y_src, int y_src_stride, const uint16_t *y_pre, + int y_pre_stride, const uint16_t *u_src, const uint16_t *v_src, + int uv_src_stride, const uint16_t *u_pre, const uint16_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, int use_whole_blk, uint32_t *y_accum, + uint16_t *y_count, const uint32_t *y_dist, const uint32_t *u_dist, + const uint32_t *v_dist, const uint32_t *const *neighbors_first, + const uint32_t *const *neighbors_second, int top_weight, + int bottom_weight) { + const int rounding = (1 << strength) >> 1; + int weight = top_weight; + + __m128i mul_first, mul_second; + + __m128i sum_row_1_first, sum_row_1_second; + __m128i sum_row_2_first, sum_row_2_second; + __m128i sum_row_3_first, sum_row_3_second; + + __m128i u_first, u_second; + __m128i v_first, v_second; + + __m128i sum_row_first; + __m128i sum_row_second; + + // Loop variables + unsigned int h; + + assert(strength >= 4 && strength <= 14 && + "invalid adjusted temporal filter strength"); + assert(block_width == 8); + + (void)block_width; + + // First row + mul_first = _mm_loadu_si128((const __m128i *)neighbors_first[0]); + mul_second = _mm_loadu_si128((const __m128i *)neighbors_second[0]); + + // Add luma values + highbd_get_sum_8(y_dist, &sum_row_2_first, &sum_row_2_second); + highbd_get_sum_8(y_dist + DIST_STRIDE, &sum_row_3_first, &sum_row_3_second); + + // We don't need to saturate here because the maximum value is UINT12_MAX ** 2 + // * 9 ~= 2**24 * 9 < 2 ** 28 < INT32_MAX + sum_row_first = _mm_add_epi32(sum_row_2_first, sum_row_3_first); + sum_row_second = _mm_add_epi32(sum_row_2_second, sum_row_3_second); + + // Add chroma values + highbd_read_chroma_dist_row_8(ss_x, u_dist, v_dist, &u_first, &u_second, + &v_first, &v_second); + + // Max value here is 2 ** 24 * (9 + 2), so no saturation is needed + sum_row_first = _mm_add_epi32(sum_row_first, u_first); + sum_row_second = _mm_add_epi32(sum_row_second, u_second); + + sum_row_first = _mm_add_epi32(sum_row_first, v_first); + sum_row_second = _mm_add_epi32(sum_row_second, v_second); + + // Get modifier and store result + highbd_average_8(&sum_row_first, &sum_row_second, &sum_row_first, + &sum_row_second, &mul_first, &mul_second, strength, rounding, + weight); + + highbd_accumulate_and_store_8(sum_row_first, sum_row_second, y_pre, y_count, + y_accum); + + y_src += y_src_stride; + y_pre += y_pre_stride; + y_count += y_pre_stride; + y_accum += y_pre_stride; + y_dist += DIST_STRIDE; + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + + // Then all the rows except the last one + mul_first = _mm_loadu_si128((const __m128i *)neighbors_first[1]); + mul_second = _mm_loadu_si128((const __m128i *)neighbors_second[1]); + + for (h = 1; h < block_height - 1; ++h) { + // Move the weight to bottom half + if (!use_whole_blk && h == block_height / 2) { + weight = bottom_weight; + } + // Shift the rows up + sum_row_1_first = sum_row_2_first; + sum_row_1_second = sum_row_2_second; + sum_row_2_first = sum_row_3_first; + sum_row_2_second = sum_row_3_second; + + // Add luma values to the modifier + sum_row_first = _mm_add_epi32(sum_row_1_first, sum_row_2_first); + sum_row_second = _mm_add_epi32(sum_row_1_second, sum_row_2_second); + + highbd_get_sum_8(y_dist + DIST_STRIDE, &sum_row_3_first, &sum_row_3_second); + + sum_row_first = _mm_add_epi32(sum_row_first, sum_row_3_first); + sum_row_second = _mm_add_epi32(sum_row_second, sum_row_3_second); + + // Add chroma values to the modifier + if (ss_y == 0 || h % 2 == 0) { + // Only calculate the new chroma distortion if we are at a pixel that + // corresponds to a new chroma row + highbd_read_chroma_dist_row_8(ss_x, u_dist, v_dist, &u_first, &u_second, + &v_first, &v_second); + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + } + + sum_row_first = _mm_add_epi32(sum_row_first, u_first); + sum_row_second = _mm_add_epi32(sum_row_second, u_second); + sum_row_first = _mm_add_epi32(sum_row_first, v_first); + sum_row_second = _mm_add_epi32(sum_row_second, v_second); + + // Get modifier and store result + highbd_average_8(&sum_row_first, &sum_row_second, &sum_row_first, + &sum_row_second, &mul_first, &mul_second, strength, + rounding, weight); + highbd_accumulate_and_store_8(sum_row_first, sum_row_second, y_pre, y_count, + y_accum); + + y_src += y_src_stride; + y_pre += y_pre_stride; + y_count += y_pre_stride; + y_accum += y_pre_stride; + y_dist += DIST_STRIDE; + } + + // The last row + mul_first = _mm_loadu_si128((const __m128i *)neighbors_first[0]); + mul_second = _mm_loadu_si128((const __m128i *)neighbors_second[0]); + + // Shift the rows up + sum_row_1_first = sum_row_2_first; + sum_row_1_second = sum_row_2_second; + sum_row_2_first = sum_row_3_first; + sum_row_2_second = sum_row_3_second; + + // Add luma values to the modifier + sum_row_first = _mm_add_epi32(sum_row_1_first, sum_row_2_first); + sum_row_second = _mm_add_epi32(sum_row_1_second, sum_row_2_second); + + // Add chroma values to the modifier + if (ss_y == 0) { + // Only calculate the new chroma distortion if we are at a pixel that + // corresponds to a new chroma row + highbd_read_chroma_dist_row_8(ss_x, u_dist, v_dist, &u_first, &u_second, + &v_first, &v_second); + } + + sum_row_first = _mm_add_epi32(sum_row_first, u_first); + sum_row_second = _mm_add_epi32(sum_row_second, u_second); + sum_row_first = _mm_add_epi32(sum_row_first, v_first); + sum_row_second = _mm_add_epi32(sum_row_second, v_second); + + // Get modifier and store result + highbd_average_8(&sum_row_first, &sum_row_second, &sum_row_first, + &sum_row_second, &mul_first, &mul_second, strength, rounding, + weight); + highbd_accumulate_and_store_8(sum_row_first, sum_row_second, y_pre, y_count, + y_accum); +} + +// Perform temporal filter for the luma component. +static void av1_highbd_apply_temporal_filter_luma( + const uint16_t *y_src, int y_src_stride, const uint16_t *y_pre, + int y_pre_stride, const uint16_t *u_src, const uint16_t *v_src, + int uv_src_stride, const uint16_t *u_pre, const uint16_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_whole_blk, + uint32_t *y_accum, uint16_t *y_count, const uint32_t *y_dist, + const uint32_t *u_dist, const uint32_t *v_dist) { + unsigned int blk_col = 0, uv_blk_col = 0; + const unsigned int blk_col_step = 8, uv_blk_col_step = 8 >> ss_x; + const unsigned int mid_width = block_width >> 1, + last_width = block_width - blk_col_step; + int top_weight = blk_fw[0], + bottom_weight = use_whole_blk ? blk_fw[0] : blk_fw[2]; + const uint32_t *const *neighbors_first; + const uint32_t *const *neighbors_second; + + // Left + neighbors_first = HIGHBD_LUMA_LEFT_COLUMN_NEIGHBORS; + neighbors_second = HIGHBD_LUMA_MIDDLE_COLUMN_NEIGHBORS; + av1_highbd_apply_temporal_filter_luma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, blk_col_step, block_height, ss_x, ss_y, + strength, use_whole_blk, y_accum + blk_col, y_count + blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, + neighbors_first, neighbors_second, top_weight, bottom_weight); + + blk_col += blk_col_step; + uv_blk_col += uv_blk_col_step; + + // Middle First + neighbors_first = HIGHBD_LUMA_MIDDLE_COLUMN_NEIGHBORS; + for (; blk_col < mid_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_highbd_apply_temporal_filter_luma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, blk_col_step, + block_height, ss_x, ss_y, strength, use_whole_blk, y_accum + blk_col, + y_count + blk_col, y_dist + blk_col, u_dist + uv_blk_col, + v_dist + uv_blk_col, neighbors_first, neighbors_second, top_weight, + bottom_weight); + } + + if (!use_whole_blk) { + top_weight = blk_fw[1]; + bottom_weight = blk_fw[3]; + } + + // Middle Second + for (; blk_col < last_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_highbd_apply_temporal_filter_luma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, blk_col_step, + block_height, ss_x, ss_y, strength, use_whole_blk, y_accum + blk_col, + y_count + blk_col, y_dist + blk_col, u_dist + uv_blk_col, + v_dist + uv_blk_col, neighbors_first, neighbors_second, top_weight, + bottom_weight); + } + + // Right + neighbors_second = HIGHBD_LUMA_RIGHT_COLUMN_NEIGHBORS; + av1_highbd_apply_temporal_filter_luma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, blk_col_step, block_height, ss_x, ss_y, + strength, use_whole_blk, y_accum + blk_col, y_count + blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, + neighbors_first, neighbors_second, top_weight, bottom_weight); +} + +// Add a row of luma distortion that corresponds to 8 chroma mods. If we are +// subsampling in x direction, then we have 16 lumas, else we have 8. +static INLINE void highbd_add_luma_dist_to_8_chroma_mod( + const uint32_t *y_dist, int ss_x, int ss_y, __m128i *u_mod_fst, + __m128i *u_mod_snd, __m128i *v_mod_fst, __m128i *v_mod_snd) { + __m128i y_reg_fst, y_reg_snd; + if (!ss_x) { + highbd_read_dist_8(y_dist, &y_reg_fst, &y_reg_snd); + if (ss_y == 1) { + __m128i y_tmp_fst, y_tmp_snd; + highbd_read_dist_8(y_dist + DIST_STRIDE, &y_tmp_fst, &y_tmp_snd); + y_reg_fst = _mm_add_epi32(y_reg_fst, y_tmp_fst); + y_reg_snd = _mm_add_epi32(y_reg_snd, y_tmp_snd); + } + } else { + // Temporary + __m128i y_fst, y_snd; + + // First 8 + highbd_read_dist_8(y_dist, &y_fst, &y_snd); + if (ss_y == 1) { + __m128i y_tmp_fst, y_tmp_snd; + highbd_read_dist_8(y_dist + DIST_STRIDE, &y_tmp_fst, &y_tmp_snd); + + y_fst = _mm_add_epi32(y_fst, y_tmp_fst); + y_snd = _mm_add_epi32(y_snd, y_tmp_snd); + } + + y_reg_fst = _mm_hadd_epi32(y_fst, y_snd); + + // Second 8 + highbd_read_dist_8(y_dist + 8, &y_fst, &y_snd); + if (ss_y == 1) { + __m128i y_tmp_fst, y_tmp_snd; + highbd_read_dist_8(y_dist + 8 + DIST_STRIDE, &y_tmp_fst, &y_tmp_snd); + + y_fst = _mm_add_epi32(y_fst, y_tmp_fst); + y_snd = _mm_add_epi32(y_snd, y_tmp_snd); + } + + y_reg_snd = _mm_hadd_epi32(y_fst, y_snd); + } + + *u_mod_fst = _mm_add_epi32(*u_mod_fst, y_reg_fst); + *u_mod_snd = _mm_add_epi32(*u_mod_snd, y_reg_snd); + *v_mod_fst = _mm_add_epi32(*v_mod_fst, y_reg_fst); + *v_mod_snd = _mm_add_epi32(*v_mod_snd, y_reg_snd); +} + +// Apply temporal filter to the chroma components. This performs temporal +// filtering on a chroma block of 8 X uv_height. If blk_fw is not NULL, use +// blk_fw as an array of size 4 for the weights for each of the 4 subblocks, +// else use top_weight for top half, and bottom weight for bottom half. +static void av1_highbd_apply_temporal_filter_chroma_8( + const uint16_t *y_src, int y_src_stride, const uint16_t *y_pre, + int y_pre_stride, const uint16_t *u_src, const uint16_t *v_src, + int uv_src_stride, const uint16_t *u_pre, const uint16_t *v_pre, + int uv_pre_stride, unsigned int uv_block_width, + unsigned int uv_block_height, int ss_x, int ss_y, int strength, + uint32_t *u_accum, uint16_t *u_count, uint32_t *v_accum, uint16_t *v_count, + const uint32_t *y_dist, const uint32_t *u_dist, const uint32_t *v_dist, + const uint32_t *const *neighbors_fst, const uint32_t *const *neighbors_snd, + int top_weight, int bottom_weight, const int *blk_fw) { + const int rounding = (1 << strength) >> 1; + int weight = top_weight; + + __m128i mul_fst, mul_snd; + + __m128i u_sum_row_1_fst, u_sum_row_2_fst, u_sum_row_3_fst; + __m128i v_sum_row_1_fst, v_sum_row_2_fst, v_sum_row_3_fst; + __m128i u_sum_row_1_snd, u_sum_row_2_snd, u_sum_row_3_snd; + __m128i v_sum_row_1_snd, v_sum_row_2_snd, v_sum_row_3_snd; + + __m128i u_sum_row_fst, v_sum_row_fst; + __m128i u_sum_row_snd, v_sum_row_snd; + + // Loop variable + unsigned int h; + + (void)uv_block_width; + + // First row + mul_fst = _mm_loadu_si128((const __m128i *)neighbors_fst[0]); + mul_snd = _mm_loadu_si128((const __m128i *)neighbors_snd[0]); + + // Add chroma values + highbd_get_sum_8(u_dist, &u_sum_row_2_fst, &u_sum_row_2_snd); + highbd_get_sum_8(u_dist + DIST_STRIDE, &u_sum_row_3_fst, &u_sum_row_3_snd); + + u_sum_row_fst = _mm_add_epi32(u_sum_row_2_fst, u_sum_row_3_fst); + u_sum_row_snd = _mm_add_epi32(u_sum_row_2_snd, u_sum_row_3_snd); + + highbd_get_sum_8(v_dist, &v_sum_row_2_fst, &v_sum_row_2_snd); + highbd_get_sum_8(v_dist + DIST_STRIDE, &v_sum_row_3_fst, &v_sum_row_3_snd); + + v_sum_row_fst = _mm_add_epi32(v_sum_row_2_fst, v_sum_row_3_fst); + v_sum_row_snd = _mm_add_epi32(v_sum_row_2_snd, v_sum_row_3_snd); + + // Add luma values + highbd_add_luma_dist_to_8_chroma_mod(y_dist, ss_x, ss_y, &u_sum_row_fst, + &u_sum_row_snd, &v_sum_row_fst, + &v_sum_row_snd); + + // Get modifier and store result + if (blk_fw) { + highbd_average_4(&u_sum_row_fst, &u_sum_row_fst, &mul_fst, strength, + rounding, blk_fw[0]); + highbd_average_4(&u_sum_row_snd, &u_sum_row_snd, &mul_snd, strength, + rounding, blk_fw[1]); + + highbd_average_4(&v_sum_row_fst, &v_sum_row_fst, &mul_fst, strength, + rounding, blk_fw[0]); + highbd_average_4(&v_sum_row_snd, &v_sum_row_snd, &mul_snd, strength, + rounding, blk_fw[1]); + + } else { + highbd_average_8(&u_sum_row_fst, &u_sum_row_snd, &u_sum_row_fst, + &u_sum_row_snd, &mul_fst, &mul_snd, strength, rounding, + weight); + highbd_average_8(&v_sum_row_fst, &v_sum_row_snd, &v_sum_row_fst, + &v_sum_row_snd, &mul_fst, &mul_snd, strength, rounding, + weight); + } + highbd_accumulate_and_store_8(u_sum_row_fst, u_sum_row_snd, u_pre, u_count, + u_accum); + highbd_accumulate_and_store_8(v_sum_row_fst, v_sum_row_snd, v_pre, v_count, + v_accum); + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + u_count += uv_pre_stride; + u_accum += uv_pre_stride; + v_count += uv_pre_stride; + v_accum += uv_pre_stride; + + y_src += y_src_stride * (1 + ss_y); + y_pre += y_pre_stride * (1 + ss_y); + y_dist += DIST_STRIDE * (1 + ss_y); + + // Then all the rows except the last one + mul_fst = _mm_loadu_si128((const __m128i *)neighbors_fst[1]); + mul_snd = _mm_loadu_si128((const __m128i *)neighbors_snd[1]); + + for (h = 1; h < uv_block_height - 1; ++h) { + // Move the weight pointer to the bottom half of the blocks + if (h == uv_block_height / 2) { + if (blk_fw) { + blk_fw += 2; + } else { + weight = bottom_weight; + } + } + + // Shift the rows up + u_sum_row_1_fst = u_sum_row_2_fst; + u_sum_row_2_fst = u_sum_row_3_fst; + u_sum_row_1_snd = u_sum_row_2_snd; + u_sum_row_2_snd = u_sum_row_3_snd; + + v_sum_row_1_fst = v_sum_row_2_fst; + v_sum_row_2_fst = v_sum_row_3_fst; + v_sum_row_1_snd = v_sum_row_2_snd; + v_sum_row_2_snd = v_sum_row_3_snd; + + // Add chroma values + u_sum_row_fst = _mm_add_epi32(u_sum_row_1_fst, u_sum_row_2_fst); + u_sum_row_snd = _mm_add_epi32(u_sum_row_1_snd, u_sum_row_2_snd); + highbd_get_sum_8(u_dist + DIST_STRIDE, &u_sum_row_3_fst, &u_sum_row_3_snd); + u_sum_row_fst = _mm_add_epi32(u_sum_row_fst, u_sum_row_3_fst); + u_sum_row_snd = _mm_add_epi32(u_sum_row_snd, u_sum_row_3_snd); + + v_sum_row_fst = _mm_add_epi32(v_sum_row_1_fst, v_sum_row_2_fst); + v_sum_row_snd = _mm_add_epi32(v_sum_row_1_snd, v_sum_row_2_snd); + highbd_get_sum_8(v_dist + DIST_STRIDE, &v_sum_row_3_fst, &v_sum_row_3_snd); + v_sum_row_fst = _mm_add_epi32(v_sum_row_fst, v_sum_row_3_fst); + v_sum_row_snd = _mm_add_epi32(v_sum_row_snd, v_sum_row_3_snd); + + // Add luma values + highbd_add_luma_dist_to_8_chroma_mod(y_dist, ss_x, ss_y, &u_sum_row_fst, + &u_sum_row_snd, &v_sum_row_fst, + &v_sum_row_snd); + + // Get modifier and store result + if (blk_fw) { + highbd_average_4(&u_sum_row_fst, &u_sum_row_fst, &mul_fst, strength, + rounding, blk_fw[0]); + highbd_average_4(&u_sum_row_snd, &u_sum_row_snd, &mul_snd, strength, + rounding, blk_fw[1]); + + highbd_average_4(&v_sum_row_fst, &v_sum_row_fst, &mul_fst, strength, + rounding, blk_fw[0]); + highbd_average_4(&v_sum_row_snd, &v_sum_row_snd, &mul_snd, strength, + rounding, blk_fw[1]); + + } else { + highbd_average_8(&u_sum_row_fst, &u_sum_row_snd, &u_sum_row_fst, + &u_sum_row_snd, &mul_fst, &mul_snd, strength, rounding, + weight); + highbd_average_8(&v_sum_row_fst, &v_sum_row_snd, &v_sum_row_fst, + &v_sum_row_snd, &mul_fst, &mul_snd, strength, rounding, + weight); + } + + highbd_accumulate_and_store_8(u_sum_row_fst, u_sum_row_snd, u_pre, u_count, + u_accum); + highbd_accumulate_and_store_8(v_sum_row_fst, v_sum_row_snd, v_pre, v_count, + v_accum); + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + u_count += uv_pre_stride; + u_accum += uv_pre_stride; + v_count += uv_pre_stride; + v_accum += uv_pre_stride; + + y_src += y_src_stride * (1 + ss_y); + y_pre += y_pre_stride * (1 + ss_y); + y_dist += DIST_STRIDE * (1 + ss_y); + } + + // The last row + mul_fst = _mm_loadu_si128((const __m128i *)neighbors_fst[0]); + mul_snd = _mm_loadu_si128((const __m128i *)neighbors_snd[0]); + + // Shift the rows up + u_sum_row_1_fst = u_sum_row_2_fst; + u_sum_row_2_fst = u_sum_row_3_fst; + u_sum_row_1_snd = u_sum_row_2_snd; + u_sum_row_2_snd = u_sum_row_3_snd; + + v_sum_row_1_fst = v_sum_row_2_fst; + v_sum_row_2_fst = v_sum_row_3_fst; + v_sum_row_1_snd = v_sum_row_2_snd; + v_sum_row_2_snd = v_sum_row_3_snd; + + // Add chroma values + u_sum_row_fst = _mm_add_epi32(u_sum_row_1_fst, u_sum_row_2_fst); + v_sum_row_fst = _mm_add_epi32(v_sum_row_1_fst, v_sum_row_2_fst); + u_sum_row_snd = _mm_add_epi32(u_sum_row_1_snd, u_sum_row_2_snd); + v_sum_row_snd = _mm_add_epi32(v_sum_row_1_snd, v_sum_row_2_snd); + + // Add luma values + highbd_add_luma_dist_to_8_chroma_mod(y_dist, ss_x, ss_y, &u_sum_row_fst, + &u_sum_row_snd, &v_sum_row_fst, + &v_sum_row_snd); + + // Get modifier and store result + if (blk_fw) { + highbd_average_4(&u_sum_row_fst, &u_sum_row_fst, &mul_fst, strength, + rounding, blk_fw[0]); + highbd_average_4(&u_sum_row_snd, &u_sum_row_snd, &mul_snd, strength, + rounding, blk_fw[1]); + + highbd_average_4(&v_sum_row_fst, &v_sum_row_fst, &mul_fst, strength, + rounding, blk_fw[0]); + highbd_average_4(&v_sum_row_snd, &v_sum_row_snd, &mul_snd, strength, + rounding, blk_fw[1]); + + } else { + highbd_average_8(&u_sum_row_fst, &u_sum_row_snd, &u_sum_row_fst, + &u_sum_row_snd, &mul_fst, &mul_snd, strength, rounding, + weight); + highbd_average_8(&v_sum_row_fst, &v_sum_row_snd, &v_sum_row_fst, + &v_sum_row_snd, &mul_fst, &mul_snd, strength, rounding, + weight); + } + + highbd_accumulate_and_store_8(u_sum_row_fst, u_sum_row_snd, u_pre, u_count, + u_accum); + highbd_accumulate_and_store_8(v_sum_row_fst, v_sum_row_snd, v_pre, v_count, + v_accum); +} + +// Perform temporal filter for the chroma components. +static void av1_highbd_apply_temporal_filter_chroma( + const uint16_t *y_src, int y_src_stride, const uint16_t *y_pre, + int y_pre_stride, const uint16_t *u_src, const uint16_t *v_src, + int uv_src_stride, const uint16_t *u_pre, const uint16_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_whole_blk, + uint32_t *u_accum, uint16_t *u_count, uint32_t *v_accum, uint16_t *v_count, + const uint32_t *y_dist, const uint32_t *u_dist, const uint32_t *v_dist) { + const unsigned int uv_width = block_width >> ss_x, + uv_height = block_height >> ss_y; + + unsigned int blk_col = 0, uv_blk_col = 0; + const unsigned int uv_blk_col_step = 8, blk_col_step = 8 << ss_x; + const unsigned int uv_mid_width = uv_width >> 1, + uv_last_width = uv_width - uv_blk_col_step; + int top_weight = blk_fw[0], + bottom_weight = use_whole_blk ? blk_fw[0] : blk_fw[2]; + const uint32_t *const *neighbors_fst; + const uint32_t *const *neighbors_snd; + + if (uv_width == 8) { + // Special Case: We are subsampling in x direction on a 16x16 block. Since + // we are operating on a row of 8 chroma pixels, we can't use the usual + // left-middle-right pattern. + assert(ss_x); + + if (ss_y) { + neighbors_fst = HIGHBD_CHROMA_DOUBLE_SS_LEFT_COLUMN_NEIGHBORS; + neighbors_snd = HIGHBD_CHROMA_DOUBLE_SS_RIGHT_COLUMN_NEIGHBORS; + } else { + neighbors_fst = HIGHBD_CHROMA_SINGLE_SS_LEFT_COLUMN_NEIGHBORS; + neighbors_snd = HIGHBD_CHROMA_SINGLE_SS_RIGHT_COLUMN_NEIGHBORS; + } + + if (use_whole_blk) { + av1_highbd_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, + neighbors_fst, neighbors_snd, top_weight, bottom_weight, NULL); + } else { + av1_highbd_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, + neighbors_fst, neighbors_snd, 0, 0, blk_fw); + } + + return; + } + + // Left + if (ss_x && ss_y) { + neighbors_fst = HIGHBD_CHROMA_DOUBLE_SS_LEFT_COLUMN_NEIGHBORS; + neighbors_snd = HIGHBD_CHROMA_DOUBLE_SS_MIDDLE_COLUMN_NEIGHBORS; + } else if (ss_x || ss_y) { + neighbors_fst = HIGHBD_CHROMA_SINGLE_SS_LEFT_COLUMN_NEIGHBORS; + neighbors_snd = HIGHBD_CHROMA_SINGLE_SS_MIDDLE_COLUMN_NEIGHBORS; + } else { + neighbors_fst = HIGHBD_CHROMA_NO_SS_LEFT_COLUMN_NEIGHBORS; + neighbors_snd = HIGHBD_CHROMA_NO_SS_MIDDLE_COLUMN_NEIGHBORS; + } + + av1_highbd_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, uv_width, uv_height, ss_x, ss_y, + strength, u_accum + uv_blk_col, u_count + uv_blk_col, + v_accum + uv_blk_col, v_count + uv_blk_col, y_dist + blk_col, + u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors_fst, neighbors_snd, + top_weight, bottom_weight, NULL); + + blk_col += blk_col_step; + uv_blk_col += uv_blk_col_step; + + // Middle First + if (ss_x && ss_y) { + neighbors_fst = HIGHBD_CHROMA_DOUBLE_SS_MIDDLE_COLUMN_NEIGHBORS; + } else if (ss_x || ss_y) { + neighbors_fst = HIGHBD_CHROMA_SINGLE_SS_MIDDLE_COLUMN_NEIGHBORS; + } else { + neighbors_fst = HIGHBD_CHROMA_NO_SS_MIDDLE_COLUMN_NEIGHBORS; + } + + for (; uv_blk_col < uv_mid_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_highbd_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, + neighbors_fst, neighbors_snd, top_weight, bottom_weight, NULL); + } + + if (!use_whole_blk) { + top_weight = blk_fw[1]; + bottom_weight = blk_fw[3]; + } + + // Middle Second + for (; uv_blk_col < uv_last_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_highbd_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, + neighbors_fst, neighbors_snd, top_weight, bottom_weight, NULL); + } + + // Right + if (ss_x && ss_y) { + neighbors_snd = HIGHBD_CHROMA_DOUBLE_SS_RIGHT_COLUMN_NEIGHBORS; + } else if (ss_x || ss_y) { + neighbors_snd = HIGHBD_CHROMA_SINGLE_SS_RIGHT_COLUMN_NEIGHBORS; + } else { + neighbors_snd = HIGHBD_CHROMA_NO_SS_RIGHT_COLUMN_NEIGHBORS; + } + + av1_highbd_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, uv_width, uv_height, ss_x, ss_y, + strength, u_accum + uv_blk_col, u_count + uv_blk_col, + v_accum + uv_blk_col, v_count + uv_blk_col, y_dist + blk_col, + u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors_fst, neighbors_snd, + top_weight, bottom_weight, NULL); +} + +void av1_highbd_apply_temporal_filter_sse4_1( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_whole_blk, + uint32_t *y_accum, uint16_t *y_count, uint32_t *u_accum, uint16_t *u_count, + uint32_t *v_accum, uint16_t *v_count) { + const unsigned int chroma_height = block_height >> ss_y, + chroma_width = block_width >> ss_x; + + DECLARE_ALIGNED(16, uint32_t, y_dist[BH * DIST_STRIDE]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, u_dist[BH * DIST_STRIDE]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, v_dist[BH * DIST_STRIDE]) = { 0 }; + + uint32_t *y_dist_ptr = y_dist + 1, *u_dist_ptr = u_dist + 1, + *v_dist_ptr = v_dist + 1; + const uint16_t *y_src_ptr = CONVERT_TO_SHORTPTR(y_src), + *u_src_ptr = CONVERT_TO_SHORTPTR(u_src), + *v_src_ptr = CONVERT_TO_SHORTPTR(v_src); + const uint16_t *y_pre_ptr = CONVERT_TO_SHORTPTR(y_pre), + *u_pre_ptr = CONVERT_TO_SHORTPTR(u_pre), + *v_pre_ptr = CONVERT_TO_SHORTPTR(v_pre); + + // Loop variables + unsigned int row, blk_col; + + assert(block_width <= BW && "block width too large"); + assert(block_height <= BH && "block height too large"); + assert(block_width % 16 == 0 && "block width must be multiple of 16"); + assert(block_height % 2 == 0 && "block height must be even"); + assert((ss_x == 0 || ss_x == 1) && (ss_y == 0 || ss_y == 1) && + "invalid chroma subsampling"); + assert(strength >= 4 && strength <= 14 && + "invalid adjusted temporal filter strength"); + assert(blk_fw[0] >= 0 && "filter weight must be positive"); + assert( + (use_whole_blk || (blk_fw[1] >= 0 && blk_fw[2] >= 0 && blk_fw[3] >= 0)) && + "subblock filter weight must be positive"); + assert(blk_fw[0] <= 2 && "sublock filter weight must be less than 2"); + assert( + (use_whole_blk || (blk_fw[1] <= 2 && blk_fw[2] <= 2 && blk_fw[3] <= 2)) && + "subblock filter weight must be less than 2"); + + // Precompute the difference squared + for (row = 0; row < block_height; row++) { + for (blk_col = 0; blk_col < block_width; blk_col += 8) { + highbd_store_dist_8(y_src_ptr + blk_col, y_pre_ptr + blk_col, + y_dist_ptr + blk_col); + } + y_src_ptr += y_src_stride; + y_pre_ptr += y_pre_stride; + y_dist_ptr += DIST_STRIDE; + } + + for (row = 0; row < chroma_height; row++) { + for (blk_col = 0; blk_col < chroma_width; blk_col += 8) { + highbd_store_dist_8(u_src_ptr + blk_col, u_pre_ptr + blk_col, + u_dist_ptr + blk_col); + highbd_store_dist_8(v_src_ptr + blk_col, v_pre_ptr + blk_col, + v_dist_ptr + blk_col); + } + + u_src_ptr += uv_src_stride; + u_pre_ptr += uv_pre_stride; + u_dist_ptr += DIST_STRIDE; + v_src_ptr += uv_src_stride; + v_pre_ptr += uv_pre_stride; + v_dist_ptr += DIST_STRIDE; + } + + y_src_ptr = CONVERT_TO_SHORTPTR(y_src), + u_src_ptr = CONVERT_TO_SHORTPTR(u_src), + v_src_ptr = CONVERT_TO_SHORTPTR(v_src); + y_pre_ptr = CONVERT_TO_SHORTPTR(y_pre), + u_pre_ptr = CONVERT_TO_SHORTPTR(u_pre), + v_pre_ptr = CONVERT_TO_SHORTPTR(v_pre); + + y_dist_ptr = y_dist + 1; + u_dist_ptr = u_dist + 1; + v_dist_ptr = v_dist + 1; + + av1_highbd_apply_temporal_filter_luma( + y_src_ptr, y_src_stride, y_pre_ptr, y_pre_stride, u_src_ptr, v_src_ptr, + uv_src_stride, u_pre_ptr, v_pre_ptr, uv_pre_stride, block_width, + block_height, ss_x, ss_y, strength, blk_fw, use_whole_blk, y_accum, + y_count, y_dist_ptr, u_dist_ptr, v_dist_ptr); + + av1_highbd_apply_temporal_filter_chroma( + y_src_ptr, y_src_stride, y_pre_ptr, y_pre_stride, u_src_ptr, v_src_ptr, + uv_src_stride, u_pre_ptr, v_pre_ptr, uv_pre_stride, block_width, + block_height, ss_x, ss_y, strength, blk_fw, use_whole_blk, u_accum, + u_count, v_accum, v_count, y_dist_ptr, u_dist_ptr, v_dist_ptr); +} diff --git a/third_party/aom/av1/encoder/x86/temporal_filter_apply_sse2.asm b/third_party/aom/av1/encoder/x86/temporal_filter_apply_sse2.asm deleted file mode 100644 index 0cae3a748a..0000000000 --- a/third_party/aom/av1/encoder/x86/temporal_filter_apply_sse2.asm +++ /dev/null @@ -1,218 +0,0 @@ -; -; Copyright (c) 2016, 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 "aom_ports/x86_abi_support.asm" - -SECTION .text - -; TODO(yunqing) The following optimization is not used since the c code changes. -; void av1_temporal_filter_apply_sse2 | arg -; (unsigned char *frame1, | 0 -; unsigned int stride, | 1 -; unsigned char *frame2, | 2 -; unsigned int block_width, | 3 -; unsigned int block_height, | 4 -; int strength, | 5 -; int filter_weight, | 6 -; unsigned int *accumulator, | 7 -; unsigned short *count) | 8 -global sym(av1_temporal_filter_apply_sse2) PRIVATE -sym(av1_temporal_filter_apply_sse2): - - push rbp - mov rbp, rsp - SHADOW_ARGS_TO_STACK 9 - SAVE_XMM 7 - GET_GOT rbx - push rsi - push rdi - ALIGN_STACK 16, rax - %define block_width 0 - %define block_height 16 - %define strength 32 - %define filter_weight 48 - %define rounding_bit 64 - %define rbp_backup 80 - %define stack_size 96 - sub rsp, stack_size - mov [rsp + rbp_backup], rbp - ; end prolog - - mov edx, arg(3) - mov [rsp + block_width], rdx - mov edx, arg(4) - mov [rsp + block_height], rdx - movd xmm6, arg(5) - movdqa [rsp + strength], xmm6 ; where strength is used, all 16 bytes are read - - ; calculate the rounding bit outside the loop - ; 0x8000 >> (16 - strength) - mov rdx, 16 - sub rdx, arg(5) ; 16 - strength - movq xmm4, rdx ; can't use rdx w/ shift - movdqa xmm5, [GLOBAL(_const_top_bit)] - psrlw xmm5, xmm4 - movdqa [rsp + rounding_bit], xmm5 - - mov rsi, arg(0) ; src/frame1 - mov rdx, arg(2) ; predictor frame - mov rdi, arg(7) ; accumulator - mov rax, arg(8) ; count - - ; dup the filter weight and store for later - movd xmm0, arg(6) ; filter_weight - pshuflw xmm0, xmm0, 0 - punpcklwd xmm0, xmm0 - movdqa [rsp + filter_weight], xmm0 - - mov rbp, arg(1) ; stride - pxor xmm7, xmm7 ; zero for extraction - - mov rcx, [rsp + block_width] - imul rcx, [rsp + block_height] - add rcx, rdx - cmp dword ptr [rsp + block_width], 8 - jne .temporal_filter_apply_load_16 - -.temporal_filter_apply_load_8: - movq xmm0, [rsi] ; first row - lea rsi, [rsi + rbp] ; += stride - punpcklbw xmm0, xmm7 ; src[ 0- 7] - movq xmm1, [rsi] ; second row - lea rsi, [rsi + rbp] ; += stride - punpcklbw xmm1, xmm7 ; src[ 8-15] - jmp .temporal_filter_apply_load_finished - -.temporal_filter_apply_load_16: - movdqa xmm0, [rsi] ; src (frame1) - lea rsi, [rsi + rbp] ; += stride - movdqa xmm1, xmm0 - punpcklbw xmm0, xmm7 ; src[ 0- 7] - punpckhbw xmm1, xmm7 ; src[ 8-15] - -.temporal_filter_apply_load_finished: - movdqa xmm2, [rdx] ; predictor (frame2) - movdqa xmm3, xmm2 - punpcklbw xmm2, xmm7 ; pred[ 0- 7] - punpckhbw xmm3, xmm7 ; pred[ 8-15] - - ; modifier = src_byte - pixel_value - psubw xmm0, xmm2 ; src - pred[ 0- 7] - psubw xmm1, xmm3 ; src - pred[ 8-15] - - ; modifier *= modifier - pmullw xmm0, xmm0 ; modifer[ 0- 7]^2 - pmullw xmm1, xmm1 ; modifer[ 8-15]^2 - - ; modifier *= 3 - pmullw xmm0, [GLOBAL(_const_3w)] - pmullw xmm1, [GLOBAL(_const_3w)] - - ; modifer += 0x8000 >> (16 - strength) - paddw xmm0, [rsp + rounding_bit] - paddw xmm1, [rsp + rounding_bit] - - ; modifier >>= strength - psrlw xmm0, [rsp + strength] - psrlw xmm1, [rsp + strength] - - ; modifier = 16 - modifier - ; saturation takes care of modifier > 16 - movdqa xmm3, [GLOBAL(_const_16w)] - movdqa xmm2, [GLOBAL(_const_16w)] - psubusw xmm3, xmm1 - psubusw xmm2, xmm0 - - ; modifier *= filter_weight - pmullw xmm2, [rsp + filter_weight] - pmullw xmm3, [rsp + filter_weight] - - ; count - movdqa xmm4, [rax] - movdqa xmm5, [rax+16] - ; += modifier - paddw xmm4, xmm2 - paddw xmm5, xmm3 - ; write back - movdqa [rax], xmm4 - movdqa [rax+16], xmm5 - lea rax, [rax + 16*2] ; count += 16*(sizeof(short)) - - ; load and extract the predictor up to shorts - pxor xmm7, xmm7 - movdqa xmm0, [rdx] - lea rdx, [rdx + 16*1] ; pred += 16*(sizeof(char)) - movdqa xmm1, xmm0 - punpcklbw xmm0, xmm7 ; pred[ 0- 7] - punpckhbw xmm1, xmm7 ; pred[ 8-15] - - ; modifier *= pixel_value - pmullw xmm0, xmm2 - pmullw xmm1, xmm3 - - ; expand to double words - movdqa xmm2, xmm0 - punpcklwd xmm0, xmm7 ; [ 0- 3] - punpckhwd xmm2, xmm7 ; [ 4- 7] - movdqa xmm3, xmm1 - punpcklwd xmm1, xmm7 ; [ 8-11] - punpckhwd xmm3, xmm7 ; [12-15] - - ; accumulator - movdqa xmm4, [rdi] - movdqa xmm5, [rdi+16] - movdqa xmm6, [rdi+32] - movdqa xmm7, [rdi+48] - ; += modifier - paddd xmm4, xmm0 - paddd xmm5, xmm2 - paddd xmm6, xmm1 - paddd xmm7, xmm3 - ; write back - movdqa [rdi], xmm4 - movdqa [rdi+16], xmm5 - movdqa [rdi+32], xmm6 - movdqa [rdi+48], xmm7 - lea rdi, [rdi + 16*4] ; accumulator += 16*(sizeof(int)) - - cmp rdx, rcx - je .temporal_filter_apply_epilog - pxor xmm7, xmm7 ; zero for extraction - cmp dword ptr [rsp + block_width], 16 - je .temporal_filter_apply_load_16 - jmp .temporal_filter_apply_load_8 - -.temporal_filter_apply_epilog: - ; begin epilog - mov rbp, [rsp + rbp_backup] - add rsp, stack_size - pop rsp - pop rdi - pop rsi - RESTORE_GOT - RESTORE_XMM - UNSHADOW_ARGS - pop rbp - ret - -SECTION_RODATA -align 16 -_const_3w: - times 8 dw 3 -align 16 -_const_top_bit: - times 8 dw 1<<15 -align 16 -_const_16w: - times 8 dw 16 diff --git a/third_party/aom/av1/encoder/x86/temporal_filter_constants.h b/third_party/aom/av1/encoder/x86/temporal_filter_constants.h new file mode 100644 index 0000000000..b3a10ddddc --- /dev/null +++ b/third_party/aom/av1/encoder/x86/temporal_filter_constants.h @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2019, 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. + */ + +#ifndef AOM_AV1_ENCODER_X86_TEMPORAL_FILTER_CONSTANTS_H_ +#define AOM_AV1_ENCODER_X86_TEMPORAL_FILTER_CONSTANTS_H_ + +// Division using multiplication and shifting. The C implementation does: +// modifier *= 3; +// modifier /= index; +// where 'modifier' is a set of summed values and 'index' is the number of +// summed values. +// +// This equation works out to (m * 3) / i which reduces to: +// m * 3/4 +// m * 1/2 +// m * 1/3 +// +// By pairing the multiply with a down shift by 16 (_mm_mulhi_epu16): +// m * C / 65536 +// we can create a C to replicate the division. +// +// m * 49152 / 65536 = m * 3/4 +// m * 32758 / 65536 = m * 1/2 +// m * 21846 / 65536 = m * 0.3333 +// +// These are loaded using an instruction expecting int16_t values but are used +// with _mm_mulhi_epu16(), which treats them as unsigned. +#define NEIGHBOR_CONSTANT_4 (int16_t)49152 +#define NEIGHBOR_CONSTANT_5 (int16_t)39322 +#define NEIGHBOR_CONSTANT_6 (int16_t)32768 +#define NEIGHBOR_CONSTANT_7 (int16_t)28087 +#define NEIGHBOR_CONSTANT_8 (int16_t)24576 +#define NEIGHBOR_CONSTANT_9 (int16_t)21846 +#define NEIGHBOR_CONSTANT_10 (int16_t)19661 +#define NEIGHBOR_CONSTANT_11 (int16_t)17874 +#define NEIGHBOR_CONSTANT_13 (int16_t)15124 + +DECLARE_ALIGNED(16, static const int16_t, LEFT_CORNER_NEIGHBORS_PLUS_1[8]) = { + NEIGHBOR_CONSTANT_5, NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7 +}; + +DECLARE_ALIGNED(16, static const int16_t, RIGHT_CORNER_NEIGHBORS_PLUS_1[8]) = { + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_5 +}; + +DECLARE_ALIGNED(16, static const int16_t, LEFT_EDGE_NEIGHBORS_PLUS_1[8]) = { + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const int16_t, RIGHT_EDGE_NEIGHBORS_PLUS_1[8]) = { + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_7 +}; + +DECLARE_ALIGNED(16, static const int16_t, MIDDLE_EDGE_NEIGHBORS_PLUS_1[8]) = { + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7, + NEIGHBOR_CONSTANT_7, NEIGHBOR_CONSTANT_7 +}; + +DECLARE_ALIGNED(16, static const int16_t, MIDDLE_CENTER_NEIGHBORS_PLUS_1[8]) = { + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const int16_t, LEFT_CORNER_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_6, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const int16_t, RIGHT_CORNER_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_6 +}; + +DECLARE_ALIGNED(16, static const int16_t, LEFT_EDGE_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11 +}; + +DECLARE_ALIGNED(16, static const int16_t, RIGHT_EDGE_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const int16_t, MIDDLE_EDGE_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const int16_t, MIDDLE_CENTER_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11 +}; + +DECLARE_ALIGNED(16, static const int16_t, TWO_CORNER_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_6, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_8, + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_6 +}; + +DECLARE_ALIGNED(16, static const int16_t, TWO_EDGE_NEIGHBORS_PLUS_2[8]) = { + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_11, + NEIGHBOR_CONSTANT_11, NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const int16_t, LEFT_CORNER_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const int16_t, RIGHT_CORNER_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const int16_t, LEFT_EDGE_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13 +}; + +DECLARE_ALIGNED(16, static const int16_t, RIGHT_EDGE_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const int16_t, MIDDLE_EDGE_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const int16_t, MIDDLE_CENTER_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13 +}; + +DECLARE_ALIGNED(16, static const int16_t, TWO_CORNER_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_8, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_10, + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const int16_t, TWO_EDGE_NEIGHBORS_PLUS_4[8]) = { + NEIGHBOR_CONSTANT_10, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_13, + NEIGHBOR_CONSTANT_13, NEIGHBOR_CONSTANT_10 +}; + +static const int16_t *const LUMA_LEFT_COLUMN_NEIGHBORS[2] = { + LEFT_CORNER_NEIGHBORS_PLUS_2, LEFT_EDGE_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const LUMA_MIDDLE_COLUMN_NEIGHBORS[2] = { + MIDDLE_EDGE_NEIGHBORS_PLUS_2, MIDDLE_CENTER_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const LUMA_RIGHT_COLUMN_NEIGHBORS[2] = { + RIGHT_CORNER_NEIGHBORS_PLUS_2, RIGHT_EDGE_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const CHROMA_NO_SS_LEFT_COLUMN_NEIGHBORS[2] = { + LEFT_CORNER_NEIGHBORS_PLUS_1, LEFT_EDGE_NEIGHBORS_PLUS_1 +}; + +static const int16_t *const CHROMA_NO_SS_MIDDLE_COLUMN_NEIGHBORS[2] = { + MIDDLE_EDGE_NEIGHBORS_PLUS_1, MIDDLE_CENTER_NEIGHBORS_PLUS_1 +}; + +static const int16_t *const CHROMA_NO_SS_RIGHT_COLUMN_NEIGHBORS[2] = { + RIGHT_CORNER_NEIGHBORS_PLUS_1, RIGHT_EDGE_NEIGHBORS_PLUS_1 +}; + +static const int16_t *const CHROMA_SINGLE_SS_LEFT_COLUMN_NEIGHBORS[2] = { + LEFT_CORNER_NEIGHBORS_PLUS_2, LEFT_EDGE_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const CHROMA_SINGLE_SS_MIDDLE_COLUMN_NEIGHBORS[2] = { + MIDDLE_EDGE_NEIGHBORS_PLUS_2, MIDDLE_CENTER_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const CHROMA_SINGLE_SS_RIGHT_COLUMN_NEIGHBORS[2] = { + RIGHT_CORNER_NEIGHBORS_PLUS_2, RIGHT_EDGE_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const CHROMA_SINGLE_SS_SINGLE_COLUMN_NEIGHBORS[2] = { + TWO_CORNER_NEIGHBORS_PLUS_2, TWO_EDGE_NEIGHBORS_PLUS_2 +}; + +static const int16_t *const CHROMA_DOUBLE_SS_LEFT_COLUMN_NEIGHBORS[2] = { + LEFT_CORNER_NEIGHBORS_PLUS_4, LEFT_EDGE_NEIGHBORS_PLUS_4 +}; + +static const int16_t *const CHROMA_DOUBLE_SS_MIDDLE_COLUMN_NEIGHBORS[2] = { + MIDDLE_EDGE_NEIGHBORS_PLUS_4, MIDDLE_CENTER_NEIGHBORS_PLUS_4 +}; + +static const int16_t *const CHROMA_DOUBLE_SS_RIGHT_COLUMN_NEIGHBORS[2] = { + RIGHT_CORNER_NEIGHBORS_PLUS_4, RIGHT_EDGE_NEIGHBORS_PLUS_4 +}; + +static const int16_t *const CHROMA_DOUBLE_SS_SINGLE_COLUMN_NEIGHBORS[2] = { + TWO_CORNER_NEIGHBORS_PLUS_4, TWO_EDGE_NEIGHBORS_PLUS_4 +}; + +#define HIGHBD_NEIGHBOR_CONSTANT_4 (uint32_t)3221225472U +#define HIGHBD_NEIGHBOR_CONSTANT_5 (uint32_t)2576980378U +#define HIGHBD_NEIGHBOR_CONSTANT_6 (uint32_t)2147483648U +#define HIGHBD_NEIGHBOR_CONSTANT_7 (uint32_t)1840700270U +#define HIGHBD_NEIGHBOR_CONSTANT_8 (uint32_t)1610612736U +#define HIGHBD_NEIGHBOR_CONSTANT_9 (uint32_t)1431655766U +#define HIGHBD_NEIGHBOR_CONSTANT_10 (uint32_t)1288490189U +#define HIGHBD_NEIGHBOR_CONSTANT_11 (uint32_t)1171354718U +#define HIGHBD_NEIGHBOR_CONSTANT_13 (uint32_t)991146300U + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_1[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_5, HIGHBD_NEIGHBOR_CONSTANT_7, + HIGHBD_NEIGHBOR_CONSTANT_7, HIGHBD_NEIGHBOR_CONSTANT_7 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_1[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_7, HIGHBD_NEIGHBOR_CONSTANT_7, + HIGHBD_NEIGHBOR_CONSTANT_7, HIGHBD_NEIGHBOR_CONSTANT_5 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_1[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_7, HIGHBD_NEIGHBOR_CONSTANT_10, + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_1[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10, + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_7 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_1[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_7, HIGHBD_NEIGHBOR_CONSTANT_7, + HIGHBD_NEIGHBOR_CONSTANT_7, HIGHBD_NEIGHBOR_CONSTANT_7 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_1[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10, + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_2[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_6, HIGHBD_NEIGHBOR_CONSTANT_8, + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_2[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_8, + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_6 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_2[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_11, + HIGHBD_NEIGHBOR_CONSTANT_11, HIGHBD_NEIGHBOR_CONSTANT_11 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_2[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_11, HIGHBD_NEIGHBOR_CONSTANT_11, + HIGHBD_NEIGHBOR_CONSTANT_11, HIGHBD_NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_2[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_8, + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_2[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_11, HIGHBD_NEIGHBOR_CONSTANT_11, + HIGHBD_NEIGHBOR_CONSTANT_11, HIGHBD_NEIGHBOR_CONSTANT_11 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_4[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_8, HIGHBD_NEIGHBOR_CONSTANT_10, + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_4[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10, + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_8 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_4[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_13, + HIGHBD_NEIGHBOR_CONSTANT_13, HIGHBD_NEIGHBOR_CONSTANT_13 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_4[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_13, HIGHBD_NEIGHBOR_CONSTANT_13, + HIGHBD_NEIGHBOR_CONSTANT_13, HIGHBD_NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_4[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10, + HIGHBD_NEIGHBOR_CONSTANT_10, HIGHBD_NEIGHBOR_CONSTANT_10 +}; + +DECLARE_ALIGNED(16, static const uint32_t, + HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_4[4]) = { + HIGHBD_NEIGHBOR_CONSTANT_13, HIGHBD_NEIGHBOR_CONSTANT_13, + HIGHBD_NEIGHBOR_CONSTANT_13, HIGHBD_NEIGHBOR_CONSTANT_13 +}; + +static const uint32_t *const HIGHBD_LUMA_LEFT_COLUMN_NEIGHBORS[2] = { + HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_2, HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_2 +}; + +static const uint32_t *const HIGHBD_LUMA_MIDDLE_COLUMN_NEIGHBORS[2] = { + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_2, HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_2 +}; + +static const uint32_t *const HIGHBD_LUMA_RIGHT_COLUMN_NEIGHBORS[2] = { + HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_2, HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_2 +}; + +static const uint32_t *const HIGHBD_CHROMA_NO_SS_LEFT_COLUMN_NEIGHBORS[2] = { + HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_1, HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_1 +}; + +static const uint32_t *const HIGHBD_CHROMA_NO_SS_MIDDLE_COLUMN_NEIGHBORS[2] = { + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_1, HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_1 +}; + +static const uint32_t *const HIGHBD_CHROMA_NO_SS_RIGHT_COLUMN_NEIGHBORS[2] = { + HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_1, HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_1 +}; + +static const uint32_t *const HIGHBD_CHROMA_SINGLE_SS_LEFT_COLUMN_NEIGHBORS[2] = + { HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_2, HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_2 }; + +static const uint32_t + *const HIGHBD_CHROMA_SINGLE_SS_MIDDLE_COLUMN_NEIGHBORS[2] = { + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_2, HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_2 + }; + +static const uint32_t *const HIGHBD_CHROMA_SINGLE_SS_RIGHT_COLUMN_NEIGHBORS[2] = + { HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_2, + HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_2 }; + +static const uint32_t *const HIGHBD_CHROMA_DOUBLE_SS_LEFT_COLUMN_NEIGHBORS[2] = + { HIGHBD_LEFT_CORNER_NEIGHBORS_PLUS_4, HIGHBD_LEFT_EDGE_NEIGHBORS_PLUS_4 }; + +static const uint32_t + *const HIGHBD_CHROMA_DOUBLE_SS_MIDDLE_COLUMN_NEIGHBORS[2] = { + HIGHBD_MIDDLE_EDGE_NEIGHBORS_PLUS_4, HIGHBD_MIDDLE_CENTER_NEIGHBORS_PLUS_4 + }; + +static const uint32_t *const HIGHBD_CHROMA_DOUBLE_SS_RIGHT_COLUMN_NEIGHBORS[2] = + { HIGHBD_RIGHT_CORNER_NEIGHBORS_PLUS_4, + HIGHBD_RIGHT_EDGE_NEIGHBORS_PLUS_4 }; + +#define DIST_STRIDE ((BW) + 2) +#endif // AOM_AV1_ENCODER_X86_TEMPORAL_FILTER_CONSTANTS_H_ diff --git a/third_party/aom/av1/encoder/x86/temporal_filter_sse4.c b/third_party/aom/av1/encoder/x86/temporal_filter_sse4.c new file mode 100644 index 0000000000..556d00cb93 --- /dev/null +++ b/third_party/aom/av1/encoder/x86/temporal_filter_sse4.c @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2019, 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 +#include + +#include "config/av1_rtcd.h" +#include "aom/aom_integer.h" +#include "av1/encoder/encoder.h" +#include "av1/encoder/temporal_filter.h" +#include "av1/encoder/x86/temporal_filter_constants.h" + +// Read in 8 pixels from a and b as 8-bit unsigned integers, compute the +// difference squared, and store as unsigned 16-bit integer to dst. +static INLINE void store_dist_8(const uint8_t *a, const uint8_t *b, + uint16_t *dst) { + const __m128i a_reg = _mm_loadl_epi64((const __m128i *)a); + const __m128i b_reg = _mm_loadl_epi64((const __m128i *)b); + + const __m128i a_first = _mm_cvtepu8_epi16(a_reg); + const __m128i b_first = _mm_cvtepu8_epi16(b_reg); + + __m128i dist_first; + + dist_first = _mm_sub_epi16(a_first, b_first); + dist_first = _mm_mullo_epi16(dist_first, dist_first); + + _mm_storeu_si128((__m128i *)dst, dist_first); +} + +static INLINE void store_dist_16(const uint8_t *a, const uint8_t *b, + uint16_t *dst) { + const __m128i zero = _mm_setzero_si128(); + const __m128i a_reg = _mm_loadu_si128((const __m128i *)a); + const __m128i b_reg = _mm_loadu_si128((const __m128i *)b); + + const __m128i a_first = _mm_cvtepu8_epi16(a_reg); + const __m128i a_second = _mm_unpackhi_epi8(a_reg, zero); + const __m128i b_first = _mm_cvtepu8_epi16(b_reg); + const __m128i b_second = _mm_unpackhi_epi8(b_reg, zero); + + __m128i dist_first, dist_second; + + dist_first = _mm_sub_epi16(a_first, b_first); + dist_second = _mm_sub_epi16(a_second, b_second); + dist_first = _mm_mullo_epi16(dist_first, dist_first); + dist_second = _mm_mullo_epi16(dist_second, dist_second); + + _mm_storeu_si128((__m128i *)dst, dist_first); + _mm_storeu_si128((__m128i *)(dst + 8), dist_second); +} + +static INLINE void read_dist_8(const uint16_t *dist, __m128i *dist_reg) { + *dist_reg = _mm_loadu_si128((const __m128i *)dist); +} + +static INLINE void read_dist_16(const uint16_t *dist, __m128i *reg_first, + __m128i *reg_second) { + read_dist_8(dist, reg_first); + read_dist_8(dist + 8, reg_second); +} + +// Average the value based on the number of values summed (9 for pixels away +// from the border, 4 for pixels in corners, and 6 for other edge values). +// +// Add in the rounding factor and shift, clamp to 16, invert and shift. Multiply +// by weight. +static __m128i average_8(__m128i sum, const __m128i *mul_constants, + const int strength, const int rounding, + const int weight) { + // _mm_srl_epi16 uses the lower 64 bit value for the shift. + const __m128i strength_u128 = _mm_set_epi32(0, 0, 0, strength); + const __m128i rounding_u16 = _mm_set1_epi16(rounding); + const __m128i weight_u16 = _mm_set1_epi16(weight); + const __m128i sixteen = _mm_set1_epi16(16); + + // modifier * 3 / index; + sum = _mm_mulhi_epu16(sum, *mul_constants); + + sum = _mm_adds_epu16(sum, rounding_u16); + sum = _mm_srl_epi16(sum, strength_u128); + + // The maximum input to this comparison is UINT16_MAX * NEIGHBOR_CONSTANT_4 + // >> 16 (also NEIGHBOR_CONSTANT_4 -1) which is 49151 / 0xbfff / -16385 + // So this needs to use the epu16 version which did not come until SSE4. + sum = _mm_min_epu16(sum, sixteen); + + sum = _mm_sub_epi16(sixteen, sum); + + return _mm_mullo_epi16(sum, weight_u16); +} + +static __m128i average_4_4(__m128i sum, const __m128i *mul_constants, + const int strength, const int rounding, + const int weight_0, const int weight_1) { + // _mm_srl_epi16 uses the lower 64 bit value for the shift. + const __m128i strength_u128 = _mm_set_epi32(0, 0, 0, strength); + const __m128i rounding_u16 = _mm_set1_epi16(rounding); + const __m128i weight_u16 = + _mm_setr_epi16(weight_0, weight_0, weight_0, weight_0, weight_1, weight_1, + weight_1, weight_1); + const __m128i sixteen = _mm_set1_epi16(16); + + // modifier * 3 / index; + sum = _mm_mulhi_epu16(sum, *mul_constants); + + sum = _mm_adds_epu16(sum, rounding_u16); + sum = _mm_srl_epi16(sum, strength_u128); + + // The maximum input to this comparison is UINT16_MAX * NEIGHBOR_CONSTANT_4 + // >> 16 (also NEIGHBOR_CONSTANT_4 -1) which is 49151 / 0xbfff / -16385 + // So this needs to use the epu16 version which did not come until SSE4. + sum = _mm_min_epu16(sum, sixteen); + + sum = _mm_sub_epi16(sixteen, sum); + + return _mm_mullo_epi16(sum, weight_u16); +} + +static INLINE void average_16(__m128i *sum_0_u16, __m128i *sum_1_u16, + const __m128i *mul_constants_0, + const __m128i *mul_constants_1, + const int strength, const int rounding, + const int weight) { + const __m128i strength_u128 = _mm_set_epi32(0, 0, 0, strength); + const __m128i rounding_u16 = _mm_set1_epi16(rounding); + const __m128i weight_u16 = _mm_set1_epi16(weight); + const __m128i sixteen = _mm_set1_epi16(16); + __m128i input_0, input_1; + + input_0 = _mm_mulhi_epu16(*sum_0_u16, *mul_constants_0); + input_0 = _mm_adds_epu16(input_0, rounding_u16); + + input_1 = _mm_mulhi_epu16(*sum_1_u16, *mul_constants_1); + input_1 = _mm_adds_epu16(input_1, rounding_u16); + + input_0 = _mm_srl_epi16(input_0, strength_u128); + input_1 = _mm_srl_epi16(input_1, strength_u128); + + input_0 = _mm_min_epu16(input_0, sixteen); + input_1 = _mm_min_epu16(input_1, sixteen); + input_0 = _mm_sub_epi16(sixteen, input_0); + input_1 = _mm_sub_epi16(sixteen, input_1); + + *sum_0_u16 = _mm_mullo_epi16(input_0, weight_u16); + *sum_1_u16 = _mm_mullo_epi16(input_1, weight_u16); +} + +// Add 'sum_u16' to 'count'. Multiply by 'pred' and add to 'accumulator.' +static void accumulate_and_store_8(const __m128i sum_u16, const uint8_t *pred, + uint16_t *count, uint32_t *accumulator) { + const __m128i pred_u8 = _mm_loadl_epi64((const __m128i *)pred); + const __m128i zero = _mm_setzero_si128(); + __m128i count_u16 = _mm_loadu_si128((const __m128i *)count); + __m128i pred_u16 = _mm_cvtepu8_epi16(pred_u8); + __m128i pred_0_u32, pred_1_u32; + __m128i accum_0_u32, accum_1_u32; + + count_u16 = _mm_adds_epu16(count_u16, sum_u16); + _mm_storeu_si128((__m128i *)count, count_u16); + + pred_u16 = _mm_mullo_epi16(sum_u16, pred_u16); + + pred_0_u32 = _mm_cvtepu16_epi32(pred_u16); + pred_1_u32 = _mm_unpackhi_epi16(pred_u16, zero); + + accum_0_u32 = _mm_loadu_si128((const __m128i *)accumulator); + accum_1_u32 = _mm_loadu_si128((const __m128i *)(accumulator + 4)); + + accum_0_u32 = _mm_add_epi32(pred_0_u32, accum_0_u32); + accum_1_u32 = _mm_add_epi32(pred_1_u32, accum_1_u32); + + _mm_storeu_si128((__m128i *)accumulator, accum_0_u32); + _mm_storeu_si128((__m128i *)(accumulator + 4), accum_1_u32); +} + +static INLINE void accumulate_and_store_16(const __m128i sum_0_u16, + const __m128i sum_1_u16, + const uint8_t *pred, uint16_t *count, + uint32_t *accumulator) { + const __m128i pred_u8 = _mm_loadu_si128((const __m128i *)pred); + const __m128i zero = _mm_setzero_si128(); + __m128i count_0_u16 = _mm_loadu_si128((const __m128i *)count), + count_1_u16 = _mm_loadu_si128((const __m128i *)(count + 8)); + __m128i pred_0_u16 = _mm_cvtepu8_epi16(pred_u8), + pred_1_u16 = _mm_unpackhi_epi8(pred_u8, zero); + __m128i pred_0_u32, pred_1_u32, pred_2_u32, pred_3_u32; + __m128i accum_0_u32, accum_1_u32, accum_2_u32, accum_3_u32; + + count_0_u16 = _mm_adds_epu16(count_0_u16, sum_0_u16); + _mm_storeu_si128((__m128i *)count, count_0_u16); + + count_1_u16 = _mm_adds_epu16(count_1_u16, sum_1_u16); + _mm_storeu_si128((__m128i *)(count + 8), count_1_u16); + + pred_0_u16 = _mm_mullo_epi16(sum_0_u16, pred_0_u16); + pred_1_u16 = _mm_mullo_epi16(sum_1_u16, pred_1_u16); + + pred_0_u32 = _mm_cvtepu16_epi32(pred_0_u16); + pred_1_u32 = _mm_unpackhi_epi16(pred_0_u16, zero); + pred_2_u32 = _mm_cvtepu16_epi32(pred_1_u16); + pred_3_u32 = _mm_unpackhi_epi16(pred_1_u16, zero); + + accum_0_u32 = _mm_loadu_si128((const __m128i *)accumulator); + accum_1_u32 = _mm_loadu_si128((const __m128i *)(accumulator + 4)); + accum_2_u32 = _mm_loadu_si128((const __m128i *)(accumulator + 8)); + accum_3_u32 = _mm_loadu_si128((const __m128i *)(accumulator + 12)); + + accum_0_u32 = _mm_add_epi32(pred_0_u32, accum_0_u32); + accum_1_u32 = _mm_add_epi32(pred_1_u32, accum_1_u32); + accum_2_u32 = _mm_add_epi32(pred_2_u32, accum_2_u32); + accum_3_u32 = _mm_add_epi32(pred_3_u32, accum_3_u32); + + _mm_storeu_si128((__m128i *)accumulator, accum_0_u32); + _mm_storeu_si128((__m128i *)(accumulator + 4), accum_1_u32); + _mm_storeu_si128((__m128i *)(accumulator + 8), accum_2_u32); + _mm_storeu_si128((__m128i *)(accumulator + 12), accum_3_u32); +} + +// Read in 8 pixels from y_dist. For each index i, compute y_dist[i-1] + +// y_dist[i] + y_dist[i+1] and store in sum as 16-bit unsigned int. +static INLINE void get_sum_8(const uint16_t *y_dist, __m128i *sum) { + __m128i dist_reg, dist_left, dist_right; + + dist_reg = _mm_loadu_si128((const __m128i *)y_dist); + dist_left = _mm_loadu_si128((const __m128i *)(y_dist - 1)); + dist_right = _mm_loadu_si128((const __m128i *)(y_dist + 1)); + + *sum = _mm_adds_epu16(dist_reg, dist_left); + *sum = _mm_adds_epu16(*sum, dist_right); +} + +// Read in 16 pixels from y_dist. For each index i, compute y_dist[i-1] + +// y_dist[i] + y_dist[i+1]. Store the result for first 8 pixels in sum_first and +// the rest in sum_second. +static INLINE void get_sum_16(const uint16_t *y_dist, __m128i *sum_first, + __m128i *sum_second) { + get_sum_8(y_dist, sum_first); + get_sum_8(y_dist + 8, sum_second); +} + +// Read in a row of chroma values corresponds to a row of 16 luma values. +static INLINE void read_chroma_dist_row_16(int ss_x, const uint16_t *u_dist, + const uint16_t *v_dist, + __m128i *u_first, __m128i *u_second, + __m128i *v_first, + __m128i *v_second) { + if (!ss_x) { + // If there is no chroma subsampling in the horizontal direction, then we + // need to load 16 entries from chroma. + read_dist_16(u_dist, u_first, u_second); + read_dist_16(v_dist, v_first, v_second); + } else { // ss_x == 1 + // Otherwise, we only need to load 8 entries + __m128i u_reg, v_reg; + + read_dist_8(u_dist, &u_reg); + + *u_first = _mm_unpacklo_epi16(u_reg, u_reg); + *u_second = _mm_unpackhi_epi16(u_reg, u_reg); + + read_dist_8(v_dist, &v_reg); + + *v_first = _mm_unpacklo_epi16(v_reg, v_reg); + *v_second = _mm_unpackhi_epi16(v_reg, v_reg); + } +} + +// Horizontal add unsigned 16-bit ints in src and store them as signed 32-bit +// int in dst. +static INLINE void hadd_epu16(__m128i *src, __m128i *dst) { + const __m128i zero = _mm_setzero_si128(); + const __m128i shift_right = _mm_srli_si128(*src, 2); + + const __m128i odd = _mm_blend_epi16(shift_right, zero, 170); + const __m128i even = _mm_blend_epi16(*src, zero, 170); + + *dst = _mm_add_epi32(even, odd); +} + +// Add a row of luma distortion to 8 corresponding chroma mods. +static INLINE void add_luma_dist_to_8_chroma_mod(const uint16_t *y_dist, + int ss_x, int ss_y, + __m128i *u_mod, + __m128i *v_mod) { + __m128i y_reg; + if (!ss_x) { + read_dist_8(y_dist, &y_reg); + if (ss_y == 1) { + __m128i y_tmp; + read_dist_8(y_dist + DIST_STRIDE, &y_tmp); + + y_reg = _mm_adds_epu16(y_reg, y_tmp); + } + } else { + __m128i y_first, y_second; + read_dist_16(y_dist, &y_first, &y_second); + if (ss_y == 1) { + __m128i y_tmp_0, y_tmp_1; + read_dist_16(y_dist + DIST_STRIDE, &y_tmp_0, &y_tmp_1); + + y_first = _mm_adds_epu16(y_first, y_tmp_0); + y_second = _mm_adds_epu16(y_second, y_tmp_1); + } + + hadd_epu16(&y_first, &y_first); + hadd_epu16(&y_second, &y_second); + + y_reg = _mm_packus_epi32(y_first, y_second); + } + + *u_mod = _mm_adds_epu16(*u_mod, y_reg); + *v_mod = _mm_adds_epu16(*v_mod, y_reg); +} + +// Apply temporal filter to the luma components. This performs temporal +// filtering on a luma block of 16 X block_height. Use blk_fw as an array of +// size 4 for the weights for each of the 4 subblocks if blk_fw is not NULL, +// else use top_weight for top half, and bottom weight for bottom half. +static void av1_apply_temporal_filter_luma_16( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, int use_whole_blk, uint32_t *y_accum, + uint16_t *y_count, const uint16_t *y_dist, const uint16_t *u_dist, + const uint16_t *v_dist, const int16_t *const *neighbors_first, + const int16_t *const *neighbors_second, int top_weight, int bottom_weight, + const int *blk_fw) { + const int rounding = (1 << strength) >> 1; + int weight = top_weight; + + __m128i mul_first, mul_second; + + __m128i sum_row_1_first, sum_row_1_second; + __m128i sum_row_2_first, sum_row_2_second; + __m128i sum_row_3_first, sum_row_3_second; + + __m128i u_first, u_second; + __m128i v_first, v_second; + + __m128i sum_row_first; + __m128i sum_row_second; + + // Loop variables + unsigned int h; + + assert(strength >= 0); + assert(strength <= 6); + + assert(block_width == 16); + + (void)block_width; + + // First row + mul_first = _mm_loadu_si128((const __m128i *)neighbors_first[0]); + mul_second = _mm_loadu_si128((const __m128i *)neighbors_second[0]); + + // Add luma values + get_sum_16(y_dist, &sum_row_2_first, &sum_row_2_second); + get_sum_16(y_dist + DIST_STRIDE, &sum_row_3_first, &sum_row_3_second); + + sum_row_first = _mm_adds_epu16(sum_row_2_first, sum_row_3_first); + sum_row_second = _mm_adds_epu16(sum_row_2_second, sum_row_3_second); + + // Add chroma values + read_chroma_dist_row_16(ss_x, u_dist, v_dist, &u_first, &u_second, &v_first, + &v_second); + + sum_row_first = _mm_adds_epu16(sum_row_first, u_first); + sum_row_second = _mm_adds_epu16(sum_row_second, u_second); + + sum_row_first = _mm_adds_epu16(sum_row_first, v_first); + sum_row_second = _mm_adds_epu16(sum_row_second, v_second); + + // Get modifier and store result + if (blk_fw) { + sum_row_first = + average_8(sum_row_first, &mul_first, strength, rounding, blk_fw[0]); + sum_row_second = + average_8(sum_row_second, &mul_second, strength, rounding, blk_fw[1]); + } else { + average_16(&sum_row_first, &sum_row_second, &mul_first, &mul_second, + strength, rounding, weight); + } + accumulate_and_store_16(sum_row_first, sum_row_second, y_pre, y_count, + y_accum); + + y_src += y_src_stride; + y_pre += y_pre_stride; + y_count += y_pre_stride; + y_accum += y_pre_stride; + y_dist += DIST_STRIDE; + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + + // Then all the rows except the last one + mul_first = _mm_loadu_si128((const __m128i *)neighbors_first[1]); + mul_second = _mm_loadu_si128((const __m128i *)neighbors_second[1]); + + for (h = 1; h < block_height - 1; ++h) { + // Move the weight to bottom half + if (!use_whole_blk && h == block_height / 2) { + if (blk_fw) { + blk_fw += 2; + } else { + weight = bottom_weight; + } + } + // Shift the rows up + sum_row_1_first = sum_row_2_first; + sum_row_1_second = sum_row_2_second; + sum_row_2_first = sum_row_3_first; + sum_row_2_second = sum_row_3_second; + + // Add luma values to the modifier + sum_row_first = _mm_adds_epu16(sum_row_1_first, sum_row_2_first); + sum_row_second = _mm_adds_epu16(sum_row_1_second, sum_row_2_second); + + get_sum_16(y_dist + DIST_STRIDE, &sum_row_3_first, &sum_row_3_second); + + sum_row_first = _mm_adds_epu16(sum_row_first, sum_row_3_first); + sum_row_second = _mm_adds_epu16(sum_row_second, sum_row_3_second); + + // Add chroma values to the modifier + if (ss_y == 0 || h % 2 == 0) { + // Only calculate the new chroma distortion if we are at a pixel that + // corresponds to a new chroma row + read_chroma_dist_row_16(ss_x, u_dist, v_dist, &u_first, &u_second, + &v_first, &v_second); + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + } + + sum_row_first = _mm_adds_epu16(sum_row_first, u_first); + sum_row_second = _mm_adds_epu16(sum_row_second, u_second); + sum_row_first = _mm_adds_epu16(sum_row_first, v_first); + sum_row_second = _mm_adds_epu16(sum_row_second, v_second); + + // Get modifier and store result + if (blk_fw) { + sum_row_first = + average_8(sum_row_first, &mul_first, strength, rounding, blk_fw[0]); + sum_row_second = + average_8(sum_row_second, &mul_second, strength, rounding, blk_fw[1]); + } else { + average_16(&sum_row_first, &sum_row_second, &mul_first, &mul_second, + strength, rounding, weight); + } + accumulate_and_store_16(sum_row_first, sum_row_second, y_pre, y_count, + y_accum); + + y_src += y_src_stride; + y_pre += y_pre_stride; + y_count += y_pre_stride; + y_accum += y_pre_stride; + y_dist += DIST_STRIDE; + } + + // The last row + mul_first = _mm_loadu_si128((const __m128i *)neighbors_first[0]); + mul_second = _mm_loadu_si128((const __m128i *)neighbors_second[0]); + + // Shift the rows up + sum_row_1_first = sum_row_2_first; + sum_row_1_second = sum_row_2_second; + sum_row_2_first = sum_row_3_first; + sum_row_2_second = sum_row_3_second; + + // Add luma values to the modifier + sum_row_first = _mm_adds_epu16(sum_row_1_first, sum_row_2_first); + sum_row_second = _mm_adds_epu16(sum_row_1_second, sum_row_2_second); + + // Add chroma values to the modifier + if (ss_y == 0) { + // Only calculate the new chroma distortion if we are at a pixel that + // corresponds to a new chroma row + read_chroma_dist_row_16(ss_x, u_dist, v_dist, &u_first, &u_second, &v_first, + &v_second); + } + + sum_row_first = _mm_adds_epu16(sum_row_first, u_first); + sum_row_second = _mm_adds_epu16(sum_row_second, u_second); + sum_row_first = _mm_adds_epu16(sum_row_first, v_first); + sum_row_second = _mm_adds_epu16(sum_row_second, v_second); + + // Get modifier and store result + if (blk_fw) { + sum_row_first = + average_8(sum_row_first, &mul_first, strength, rounding, blk_fw[0]); + sum_row_second = + average_8(sum_row_second, &mul_second, strength, rounding, blk_fw[1]); + } else { + average_16(&sum_row_first, &sum_row_second, &mul_first, &mul_second, + strength, rounding, weight); + } + accumulate_and_store_16(sum_row_first, sum_row_second, y_pre, y_count, + y_accum); +} + +// Perform temporal filter for the luma component. +static void av1_apply_temporal_filter_luma( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_whole_blk, + uint32_t *y_accum, uint16_t *y_count, const uint16_t *y_dist, + const uint16_t *u_dist, const uint16_t *v_dist) { + unsigned int blk_col = 0, uv_blk_col = 0; + const unsigned int blk_col_step = 16, uv_blk_col_step = 16 >> ss_x; + const unsigned int mid_width = block_width >> 1, + last_width = block_width - blk_col_step; + int top_weight = blk_fw[0], + bottom_weight = use_whole_blk ? blk_fw[0] : blk_fw[2]; + const int16_t *const *neighbors_first; + const int16_t *const *neighbors_second; + + if (block_width == 16) { + // Special Case: The blockwidth is 16 and we are operating on a row of 16 + // chroma pixels. In this case, we can't use the usualy left-midle-right + // pattern. We also don't support splitting now. + neighbors_first = LUMA_LEFT_COLUMN_NEIGHBORS; + neighbors_second = LUMA_RIGHT_COLUMN_NEIGHBORS; + if (use_whole_blk) { + av1_apply_temporal_filter_luma_16( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, 16, + block_height, ss_x, ss_y, strength, use_whole_blk, y_accum + blk_col, + y_count + blk_col, y_dist + blk_col, u_dist + uv_blk_col, + v_dist + uv_blk_col, neighbors_first, neighbors_second, top_weight, + bottom_weight, NULL); + } else { + av1_apply_temporal_filter_luma_16( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, 16, + block_height, ss_x, ss_y, strength, use_whole_blk, y_accum + blk_col, + y_count + blk_col, y_dist + blk_col, u_dist + uv_blk_col, + v_dist + uv_blk_col, neighbors_first, neighbors_second, 0, 0, blk_fw); + } + + return; + } + + // Left + neighbors_first = LUMA_LEFT_COLUMN_NEIGHBORS; + neighbors_second = LUMA_MIDDLE_COLUMN_NEIGHBORS; + av1_apply_temporal_filter_luma_16( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, 16, block_height, ss_x, ss_y, strength, + use_whole_blk, y_accum + blk_col, y_count + blk_col, y_dist + blk_col, + u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors_first, + neighbors_second, top_weight, bottom_weight, NULL); + + blk_col += blk_col_step; + uv_blk_col += uv_blk_col_step; + + // Middle First + neighbors_first = LUMA_MIDDLE_COLUMN_NEIGHBORS; + for (; blk_col < mid_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_apply_temporal_filter_luma_16( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, 16, block_height, + ss_x, ss_y, strength, use_whole_blk, y_accum + blk_col, + y_count + blk_col, y_dist + blk_col, u_dist + uv_blk_col, + v_dist + uv_blk_col, neighbors_first, neighbors_second, top_weight, + bottom_weight, NULL); + } + + if (!use_whole_blk) { + top_weight = blk_fw[1]; + bottom_weight = blk_fw[3]; + } + + // Middle Second + for (; blk_col < last_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_apply_temporal_filter_luma_16( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, 16, block_height, + ss_x, ss_y, strength, use_whole_blk, y_accum + blk_col, + y_count + blk_col, y_dist + blk_col, u_dist + uv_blk_col, + v_dist + uv_blk_col, neighbors_first, neighbors_second, top_weight, + bottom_weight, NULL); + } + + // Right + neighbors_second = LUMA_RIGHT_COLUMN_NEIGHBORS; + av1_apply_temporal_filter_luma_16( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, 16, block_height, ss_x, ss_y, strength, + use_whole_blk, y_accum + blk_col, y_count + blk_col, y_dist + blk_col, + u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors_first, + neighbors_second, top_weight, bottom_weight, NULL); +} + +// Apply temporal filter to the chroma components. This performs temporal +// filtering on a chroma block of 8 X uv_height. If blk_fw is not NULL, use +// blk_fw as an array of size 4 for the weights for each of the 4 subblocks, +// else use top_weight for top half, and bottom weight for bottom half. +static void av1_apply_temporal_filter_chroma_8( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int uv_block_width, + unsigned int uv_block_height, int ss_x, int ss_y, int strength, + uint32_t *u_accum, uint16_t *u_count, uint32_t *v_accum, uint16_t *v_count, + const uint16_t *y_dist, const uint16_t *u_dist, const uint16_t *v_dist, + const int16_t *const *neighbors, int top_weight, int bottom_weight, + const int *blk_fw) { + const int rounding = (1 << strength) >> 1; + int weight = top_weight; + + __m128i mul; + + __m128i u_sum_row_1, u_sum_row_2, u_sum_row_3; + __m128i v_sum_row_1, v_sum_row_2, v_sum_row_3; + + __m128i u_sum_row, v_sum_row; + + // Loop variable + unsigned int h; + + (void)uv_block_width; + + // First row + mul = _mm_loadu_si128((const __m128i *)neighbors[0]); + + // Add chroma values + get_sum_8(u_dist, &u_sum_row_2); + get_sum_8(u_dist + DIST_STRIDE, &u_sum_row_3); + + u_sum_row = _mm_adds_epu16(u_sum_row_2, u_sum_row_3); + + get_sum_8(v_dist, &v_sum_row_2); + get_sum_8(v_dist + DIST_STRIDE, &v_sum_row_3); + + v_sum_row = _mm_adds_epu16(v_sum_row_2, v_sum_row_3); + + // Add luma values + add_luma_dist_to_8_chroma_mod(y_dist, ss_x, ss_y, &u_sum_row, &v_sum_row); + + // Get modifier and store result + if (blk_fw) { + u_sum_row = + average_4_4(u_sum_row, &mul, strength, rounding, blk_fw[0], blk_fw[1]); + v_sum_row = + average_4_4(v_sum_row, &mul, strength, rounding, blk_fw[0], blk_fw[1]); + } else { + u_sum_row = average_8(u_sum_row, &mul, strength, rounding, weight); + v_sum_row = average_8(v_sum_row, &mul, strength, rounding, weight); + } + accumulate_and_store_8(u_sum_row, u_pre, u_count, u_accum); + accumulate_and_store_8(v_sum_row, v_pre, v_count, v_accum); + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + u_count += uv_pre_stride; + u_accum += uv_pre_stride; + v_count += uv_pre_stride; + v_accum += uv_pre_stride; + + y_src += y_src_stride * (1 + ss_y); + y_pre += y_pre_stride * (1 + ss_y); + y_dist += DIST_STRIDE * (1 + ss_y); + + // Then all the rows except the last one + mul = _mm_loadu_si128((const __m128i *)neighbors[1]); + + for (h = 1; h < uv_block_height - 1; ++h) { + // Move the weight pointer to the bottom half of the blocks + if (h == uv_block_height / 2) { + if (blk_fw) { + blk_fw += 2; + } else { + weight = bottom_weight; + } + } + + // Shift the rows up + u_sum_row_1 = u_sum_row_2; + u_sum_row_2 = u_sum_row_3; + + v_sum_row_1 = v_sum_row_2; + v_sum_row_2 = v_sum_row_3; + + // Add chroma values + u_sum_row = _mm_adds_epu16(u_sum_row_1, u_sum_row_2); + get_sum_8(u_dist + DIST_STRIDE, &u_sum_row_3); + u_sum_row = _mm_adds_epu16(u_sum_row, u_sum_row_3); + + v_sum_row = _mm_adds_epu16(v_sum_row_1, v_sum_row_2); + get_sum_8(v_dist + DIST_STRIDE, &v_sum_row_3); + v_sum_row = _mm_adds_epu16(v_sum_row, v_sum_row_3); + + // Add luma values + add_luma_dist_to_8_chroma_mod(y_dist, ss_x, ss_y, &u_sum_row, &v_sum_row); + + // Get modifier and store result + if (blk_fw) { + u_sum_row = average_4_4(u_sum_row, &mul, strength, rounding, blk_fw[0], + blk_fw[1]); + v_sum_row = average_4_4(v_sum_row, &mul, strength, rounding, blk_fw[0], + blk_fw[1]); + } else { + u_sum_row = average_8(u_sum_row, &mul, strength, rounding, weight); + v_sum_row = average_8(v_sum_row, &mul, strength, rounding, weight); + } + + accumulate_and_store_8(u_sum_row, u_pre, u_count, u_accum); + accumulate_and_store_8(v_sum_row, v_pre, v_count, v_accum); + + u_src += uv_src_stride; + u_pre += uv_pre_stride; + u_dist += DIST_STRIDE; + v_src += uv_src_stride; + v_pre += uv_pre_stride; + v_dist += DIST_STRIDE; + u_count += uv_pre_stride; + u_accum += uv_pre_stride; + v_count += uv_pre_stride; + v_accum += uv_pre_stride; + + y_src += y_src_stride * (1 + ss_y); + y_pre += y_pre_stride * (1 + ss_y); + y_dist += DIST_STRIDE * (1 + ss_y); + } + + // The last row + mul = _mm_loadu_si128((const __m128i *)neighbors[0]); + + // Shift the rows up + u_sum_row_1 = u_sum_row_2; + u_sum_row_2 = u_sum_row_3; + + v_sum_row_1 = v_sum_row_2; + v_sum_row_2 = v_sum_row_3; + + // Add chroma values + u_sum_row = _mm_adds_epu16(u_sum_row_1, u_sum_row_2); + v_sum_row = _mm_adds_epu16(v_sum_row_1, v_sum_row_2); + + // Add luma values + add_luma_dist_to_8_chroma_mod(y_dist, ss_x, ss_y, &u_sum_row, &v_sum_row); + + // Get modifier and store result + if (blk_fw) { + u_sum_row = + average_4_4(u_sum_row, &mul, strength, rounding, blk_fw[0], blk_fw[1]); + v_sum_row = + average_4_4(v_sum_row, &mul, strength, rounding, blk_fw[0], blk_fw[1]); + } else { + u_sum_row = average_8(u_sum_row, &mul, strength, rounding, weight); + v_sum_row = average_8(v_sum_row, &mul, strength, rounding, weight); + } + + accumulate_and_store_8(u_sum_row, u_pre, u_count, u_accum); + accumulate_and_store_8(v_sum_row, v_pre, v_count, v_accum); +} + +// Perform temporal filter for the chroma components. +static void av1_apply_temporal_filter_chroma( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_whole_blk, + uint32_t *u_accum, uint16_t *u_count, uint32_t *v_accum, uint16_t *v_count, + const uint16_t *y_dist, const uint16_t *u_dist, const uint16_t *v_dist) { + const unsigned int uv_width = block_width >> ss_x, + uv_height = block_height >> ss_y; + + unsigned int blk_col = 0, uv_blk_col = 0; + const unsigned int uv_blk_col_step = 8, blk_col_step = 8 << ss_x; + const unsigned int uv_mid_width = uv_width >> 1, + uv_last_width = uv_width - uv_blk_col_step; + int top_weight = blk_fw[0], + bottom_weight = use_whole_blk ? blk_fw[0] : blk_fw[2]; + const int16_t *const *neighbors; + + if (uv_width == 8) { + // Special Case: We are subsampling in x direction on a 16x16 block. Since + // we are operating on a row of 8 chroma pixels, we can't use the usual + // left-middle-right pattern. + assert(ss_x); + + if (ss_y) { + neighbors = CHROMA_DOUBLE_SS_SINGLE_COLUMN_NEIGHBORS; + } else { + neighbors = CHROMA_SINGLE_SS_SINGLE_COLUMN_NEIGHBORS; + } + + if (use_whole_blk) { + av1_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors, + top_weight, bottom_weight, NULL); + } else { + av1_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors, + 0, 0, blk_fw); + } + + return; + } + + // Left + if (ss_x && ss_y) { + neighbors = CHROMA_DOUBLE_SS_LEFT_COLUMN_NEIGHBORS; + } else if (ss_x || ss_y) { + neighbors = CHROMA_SINGLE_SS_LEFT_COLUMN_NEIGHBORS; + } else { + neighbors = CHROMA_NO_SS_LEFT_COLUMN_NEIGHBORS; + } + + av1_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, uv_width, uv_height, ss_x, ss_y, + strength, u_accum + uv_blk_col, u_count + uv_blk_col, + v_accum + uv_blk_col, v_count + uv_blk_col, y_dist + blk_col, + u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors, top_weight, + bottom_weight, NULL); + + blk_col += blk_col_step; + uv_blk_col += uv_blk_col_step; + + // Middle First + if (ss_x && ss_y) { + neighbors = CHROMA_DOUBLE_SS_MIDDLE_COLUMN_NEIGHBORS; + } else if (ss_x || ss_y) { + neighbors = CHROMA_SINGLE_SS_MIDDLE_COLUMN_NEIGHBORS; + } else { + neighbors = CHROMA_NO_SS_MIDDLE_COLUMN_NEIGHBORS; + } + + for (; uv_blk_col < uv_mid_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors, + top_weight, bottom_weight, NULL); + } + + if (!use_whole_blk) { + top_weight = blk_fw[1]; + bottom_weight = blk_fw[3]; + } + + // Middle Second + for (; uv_blk_col < uv_last_width; + blk_col += blk_col_step, uv_blk_col += uv_blk_col_step) { + av1_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, + u_pre + uv_blk_col, v_pre + uv_blk_col, uv_pre_stride, uv_width, + uv_height, ss_x, ss_y, strength, u_accum + uv_blk_col, + u_count + uv_blk_col, v_accum + uv_blk_col, v_count + uv_blk_col, + y_dist + blk_col, u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors, + top_weight, bottom_weight, NULL); + } + + // Right + if (ss_x && ss_y) { + neighbors = CHROMA_DOUBLE_SS_RIGHT_COLUMN_NEIGHBORS; + } else if (ss_x || ss_y) { + neighbors = CHROMA_SINGLE_SS_RIGHT_COLUMN_NEIGHBORS; + } else { + neighbors = CHROMA_NO_SS_RIGHT_COLUMN_NEIGHBORS; + } + + av1_apply_temporal_filter_chroma_8( + y_src + blk_col, y_src_stride, y_pre + blk_col, y_pre_stride, + u_src + uv_blk_col, v_src + uv_blk_col, uv_src_stride, u_pre + uv_blk_col, + v_pre + uv_blk_col, uv_pre_stride, uv_width, uv_height, ss_x, ss_y, + strength, u_accum + uv_blk_col, u_count + uv_blk_col, + v_accum + uv_blk_col, v_count + uv_blk_col, y_dist + blk_col, + u_dist + uv_blk_col, v_dist + uv_blk_col, neighbors, top_weight, + bottom_weight, NULL); +} + +void av1_apply_temporal_filter_sse4_1( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_whole_blk, + uint32_t *y_accum, uint16_t *y_count, uint32_t *u_accum, uint16_t *u_count, + uint32_t *v_accum, uint16_t *v_count) { + const unsigned int chroma_height = block_height >> ss_y, + chroma_width = block_width >> ss_x; + + DECLARE_ALIGNED(16, uint16_t, y_dist[BH * DIST_STRIDE]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, u_dist[BH * DIST_STRIDE]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, v_dist[BH * DIST_STRIDE]) = { 0 }; + const int *blk_fw_ptr = blk_fw; + + uint16_t *y_dist_ptr = y_dist + 1, *u_dist_ptr = u_dist + 1, + *v_dist_ptr = v_dist + 1; + const uint8_t *y_src_ptr = y_src, *u_src_ptr = u_src, *v_src_ptr = v_src; + const uint8_t *y_pre_ptr = y_pre, *u_pre_ptr = u_pre, *v_pre_ptr = v_pre; + + // Loop variables + unsigned int row, blk_col; + + assert(block_width <= BW && "block width too large"); + assert(block_height <= BH && "block height too large"); + assert(block_width % 16 == 0 && "block width must be multiple of 16"); + assert(block_height % 2 == 0 && "block height must be even"); + assert((ss_x == 0 || ss_x == 1) && (ss_y == 0 || ss_y == 1) && + "invalid chroma subsampling"); + assert(strength >= 0 && strength <= 6 && "invalid temporal filter strength"); + assert(blk_fw[0] >= 0 && "filter weight must be positive"); + assert( + (use_whole_blk || (blk_fw[1] >= 0 && blk_fw[2] >= 0 && blk_fw[3] >= 0)) && + "subblock filter weight must be positive"); + assert(blk_fw[0] <= 2 && "sublock filter weight must be less than 2"); + assert( + (use_whole_blk || (blk_fw[1] <= 2 && blk_fw[2] <= 2 && blk_fw[3] <= 2)) && + "subblock filter weight must be less than 2"); + + // Precompute the difference sqaured + for (row = 0; row < block_height; row++) { + for (blk_col = 0; blk_col < block_width; blk_col += 16) { + store_dist_16(y_src_ptr + blk_col, y_pre_ptr + blk_col, + y_dist_ptr + blk_col); + } + y_src_ptr += y_src_stride; + y_pre_ptr += y_pre_stride; + y_dist_ptr += DIST_STRIDE; + } + + for (row = 0; row < chroma_height; row++) { + for (blk_col = 0; blk_col < chroma_width; blk_col += 8) { + store_dist_8(u_src_ptr + blk_col, u_pre_ptr + blk_col, + u_dist_ptr + blk_col); + store_dist_8(v_src_ptr + blk_col, v_pre_ptr + blk_col, + v_dist_ptr + blk_col); + } + + u_src_ptr += uv_src_stride; + u_pre_ptr += uv_pre_stride; + u_dist_ptr += DIST_STRIDE; + v_src_ptr += uv_src_stride; + v_pre_ptr += uv_pre_stride; + v_dist_ptr += DIST_STRIDE; + } + + y_dist_ptr = y_dist + 1; + u_dist_ptr = u_dist + 1; + v_dist_ptr = v_dist + 1; + + av1_apply_temporal_filter_luma( + y_src, y_src_stride, y_pre, y_pre_stride, u_src, v_src, uv_src_stride, + u_pre, v_pre, uv_pre_stride, block_width, block_height, ss_x, ss_y, + strength, blk_fw_ptr, use_whole_blk, y_accum, y_count, y_dist_ptr, + u_dist_ptr, v_dist_ptr); + + av1_apply_temporal_filter_chroma( + y_src, y_src_stride, y_pre, y_pre_stride, u_src, v_src, uv_src_stride, + u_pre, v_pre, uv_pre_stride, block_width, block_height, ss_x, ss_y, + strength, blk_fw_ptr, use_whole_blk, u_accum, u_count, v_accum, v_count, + y_dist_ptr, u_dist_ptr, v_dist_ptr); +} diff --git a/third_party/aom/build/cmake/aom_config_defaults.cmake b/third_party/aom/build/cmake/aom_config_defaults.cmake index 47aba55af0..f498acddea 100644 --- a/third_party/aom/build/cmake/aom_config_defaults.cmake +++ b/third_party/aom/build/cmake/aom_config_defaults.cmake @@ -120,18 +120,19 @@ set_aom_config_var(CONFIG_SPEED_STATS 0 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_COLLECT_RD_STATS 0 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_DIST_8X8 0 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_ENTROPY_STATS 0 NUMBER "AV1 experiment flag.") -set_aom_config_var(CONFIG_FP_MB_STATS 0 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_INTER_STATS_ONLY 0 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_RD_DEBUG 0 NUMBER "AV1 experiment flag.") -set_aom_config_var(CONFIG_2PASS_PARTITION_SEARCH_LVL 1 NUMBER +set_aom_config_var(CONFIG_2PASS_PARTITION_SEARCH_LVL_START 1 NUMBER + "AV1 experiment flag.") +set_aom_config_var(CONFIG_2PASS_PARTITION_SEARCH_LVL_END 3 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_SHARP_SETTINGS 0 NUMBER "AV1 experiment flag.") -set_aom_config_var(CONFIG_ONE_PASS_SVM 0 NUMBER "AV1 experiment flag.") set_aom_config_var(CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8 1 NUMBER "Disable full_pixel_motion_search_based_split on BLOCK_8X8.") set_aom_config_var(CONFIG_COLLECT_PARTITION_STATS 0 NUMBER "Collect stats on partition decisions.") - +set_aom_config_var(CONFIG_COLLECT_COMPONENT_TIMING 0 NUMBER + "Collect encoding component timing information.") # # Variables in this section control optional features of the build system. # diff --git a/third_party/aom/build/cmake/toolchains/armv7-linux-gcc.cmake b/third_party/aom/build/cmake/toolchains/armv7-linux-gcc.cmake index 7d3d63085e..6cbc2a8cf7 100644 --- a/third_party/aom/build/cmake/toolchains/armv7-linux-gcc.cmake +++ b/third_party/aom/build/cmake/toolchains/armv7-linux-gcc.cmake @@ -28,16 +28,13 @@ endif() set(CMAKE_C_COMPILER ${CROSS}gcc) set(CMAKE_CXX_COMPILER ${CROSS}g++) set(AS_EXECUTABLE ${CROSS}as) -set(CMAKE_C_COMPILER_ARG1 - "-march=armv7-a -mfpu=neon ${AOM_EXTRA_TOOLCHAIN_FLAGS}") -set(CMAKE_CXX_COMPILER_ARG1 - "-march=armv7-a -mfpu=neon ${AOM_EXTRA_TOOLCHAIN_FLAGS}") +set(CMAKE_C_COMPILER_ARG1 "-march=armv7-a ${AOM_EXTRA_TOOLCHAIN_FLAGS}") +set(CMAKE_CXX_COMPILER_ARG1 "-march=armv7-a ${AOM_EXTRA_TOOLCHAIN_FLAGS}") set(AOM_AS_FLAGS --defsym ARCHITECTURE=7 -march=armv7-a -mfpu=neon ${AOM_EXTRA_TOOLCHAIN_FLAGS}) set(CMAKE_SYSTEM_PROCESSOR "armv7") -# No intrinsics flag required for armv7-linux-gcc. -set(AOM_NEON_INTRIN_FLAG "") +set(AOM_NEON_INTRIN_FLAG "-mfpu=neon") # No runtime cpu detect for armv7-linux-gcc. set(CONFIG_RUNTIME_CPU_DETECT 0 CACHE NUMBER "") diff --git a/third_party/aom/examples/inspect.c b/third_party/aom/examples/inspect.c index 050e3da3da..9ca2a02c10 100644 --- a/third_party/aom/examples/inspect.c +++ b/third_party/aom/examples/inspect.c @@ -62,7 +62,10 @@ typedef enum { SEGMENT_ID_LAYER = 1 << 14, MOTION_MODE_LAYER = 1 << 15, COMPOUND_TYPE_LAYER = 1 << 16, - ALL_LAYERS = (1 << 17) - 1 + INTRABC_LAYER = 1 << 17, + PALETTE_LAYER = 1 << 18, + UV_PALETTE_LAYER = 1 << 19, + ALL_LAYERS = (1 << 20) - 1 } LayerType; static LayerType layers = 0; @@ -106,13 +109,19 @@ static const arg_def_t dump_delta_q_arg = ARG_DEF("dq", "delta_q", 0, "Dump QIndex"); static const arg_def_t dump_seg_id_arg = ARG_DEF("si", "seg_id", 0, "Dump Segment ID"); +static const arg_def_t dump_intrabc_arg = + ARG_DEF("ibc", "intrabc", 0, "Dump If IntraBC Is Used"); +static const arg_def_t dump_palette_arg = + ARG_DEF("plt", "palette", 0, "Dump Palette Size"); +static const arg_def_t dump_uv_palette_arg = + ARG_DEF("uvp", "uv_palette", 0, "Dump UV Palette Size"); static const arg_def_t usage_arg = ARG_DEF("h", "help", 0, "Help"); static const arg_def_t skip_non_transform_arg = ARG_DEF( "snt", "skip_non_transform", 1, "Skip is counted as a non transform."); static const arg_def_t combined_arg = ARG_DEF("comb", "combined", 1, "combinining parameters into one output."); -int combined_parm_list[5]; +int combined_parm_list[15]; int combined_parm_count = 0; static const arg_def_t *main_args[] = { &limit_arg, @@ -137,6 +146,9 @@ static const arg_def_t *main_args[] = { &limit_arg, &dump_motion_vectors_arg, &dump_delta_q_arg, &dump_seg_id_arg, + &dump_intrabc_arg, + &dump_palette_arg, + &dump_uv_palette_arg, &usage_arg, &skip_non_transform_arg, &combined_arg, @@ -236,6 +248,16 @@ const map_entry uv_prediction_mode_map[] = { const map_entry skip_map[] = { ENUM(SKIP), ENUM(NO_SKIP), LAST_ENUM }; +const map_entry intrabc_map[] = { + { "INTRABC", 1 }, { "NO_INTRABC", 0 }, LAST_ENUM +}; + +const map_entry palette_map[] = { + { "ZERO_COLORS", 0 }, { "TWO_COLORS", 2 }, { "THREE_COLORS", 3 }, + { "FOUR_COLORS", 4 }, { "FIVE_COLORS", 5 }, { "SIX_COLORS", 6 }, + { "SEVEN_COLORS", 7 }, { "EIGHT_COLORS", 8 }, LAST_ENUM +}; + const map_entry config_map[] = { ENUM(MI_SIZE), LAST_ENUM }; static const char *exec_name; @@ -666,6 +688,18 @@ void inspect(void *pbi, void *data) { if (layers & MOTION_VECTORS_LAYER) { buf += put_motion_vectors(buf); } + if (layers & INTRABC_LAYER) { + buf += put_block_info(buf, intrabc_map, "intrabc", + offsetof(insp_mi_data, intrabc), 0); + } + if (layers & PALETTE_LAYER) { + buf += put_block_info(buf, palette_map, "palette", + offsetof(insp_mi_data, palette), 0); + } + if (layers & UV_PALETTE_LAYER) { + buf += put_block_info(buf, palette_map, "uv_palette", + offsetof(insp_mi_data, uv_palette), 0); + } if (combined_parm_count > 0) buf += put_combined(buf); if (layers & REFERENCE_FRAME_LAYER) { buf += put_block_info(buf, refs_map, "referenceFrame", @@ -858,6 +892,12 @@ static void parse_args(char **argv) { layers |= Q_INDEX_LAYER; else if (arg_match(&arg, &dump_seg_id_arg, argi)) layers |= SEGMENT_ID_LAYER; + else if (arg_match(&arg, &dump_intrabc_arg, argi)) + layers |= INTRABC_LAYER; + else if (arg_match(&arg, &dump_palette_arg, argi)) + layers |= PALETTE_LAYER; + else if (arg_match(&arg, &dump_uv_palette_arg, argi)) + layers |= UV_PALETTE_LAYER; else if (arg_match(&arg, &dump_all_arg, argi)) layers |= ALL_LAYERS; else if (arg_match(&arg, &compress_arg, argi)) diff --git a/third_party/aom/test/av1_fwd_txfm2d_test.cc b/third_party/aom/test/av1_fwd_txfm2d_test.cc index d55085f069..eb09cb15f3 100644 --- a/third_party/aom/test/av1_fwd_txfm2d_test.cc +++ b/third_party/aom/test/av1_fwd_txfm2d_test.cc @@ -288,6 +288,68 @@ void AV1FwdTxfm2dMatchTest(TX_SIZE tx_size, lowbd_fwd_txfm_func target_func) { } } +void AV1FwdTxfm2dSpeedTest(TX_SIZE tx_size, lowbd_fwd_txfm_func target_func) { + TxfmParam param; + memset(¶m, 0, sizeof(param)); + const int rows = tx_size_high[tx_size]; + const int cols = tx_size_wide[tx_size]; + const int num_loops = 1000000 / (rows * cols); + + for (int i = 0; i < 2; ++i) { + const int bd = 8; + for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) { + if (libaom_test::IsTxSizeTypeValid( + tx_size, static_cast(tx_type)) == false) { + continue; + } + + FwdTxfm2dFunc ref_func = libaom_test::fwd_txfm_func_ls[tx_size]; + if (ref_func != NULL) { + DECLARE_ALIGNED(32, int16_t, input[64 * 64]) = { 0 }; + DECLARE_ALIGNED(32, int32_t, output[64 * 64]); + DECLARE_ALIGNED(32, int32_t, ref_output[64 * 64]); + int input_stride = 64; + ACMRandom rnd(ACMRandom::DeterministicSeed()); + + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < cols; ++c) { + input[r * input_stride + c] = rnd.Rand16() % (1 << bd); + } + } + + param.tx_type = (TX_TYPE)tx_type; + param.tx_size = (TX_SIZE)tx_size; + param.tx_set_type = EXT_TX_SET_ALL16; + param.bd = bd; + + aom_usec_timer ref_timer, test_timer; + + aom_usec_timer_start(&ref_timer); + for (int i = 0; i < num_loops; ++i) { + ref_func(input, ref_output, input_stride, (TX_TYPE)tx_type, bd); + } + aom_usec_timer_mark(&ref_timer); + const int elapsed_time_c = + static_cast(aom_usec_timer_elapsed(&ref_timer)); + + aom_usec_timer_start(&test_timer); + for (int i = 0; i < num_loops; ++i) { + target_func(input, output, input_stride, ¶m); + } + aom_usec_timer_mark(&test_timer); + const int elapsed_time_simd = + static_cast(aom_usec_timer_elapsed(&test_timer)); + + printf( + "txfm_size[%d] \t txfm_type[%d] \t c_time=%d \t simd_time=%d \t " + "gain=%d \n", + tx_size, tx_type, elapsed_time_c, elapsed_time_simd, + (elapsed_time_c / elapsed_time_simd)); + } + } + } +} + typedef ::testing::tuple LbdFwdTxfm2dParam; class AV1FwdTxfm2dTest : public ::testing::TestWithParam {}; @@ -295,7 +357,9 @@ class AV1FwdTxfm2dTest : public ::testing::TestWithParam {}; TEST_P(AV1FwdTxfm2dTest, match) { AV1FwdTxfm2dMatchTest(GET_PARAM(0), GET_PARAM(1)); } - +TEST_P(AV1FwdTxfm2dTest, DISABLED_Speed) { + AV1FwdTxfm2dSpeedTest(GET_PARAM(0), GET_PARAM(1)); +} using ::testing::Combine; using ::testing::Values; using ::testing::ValuesIn; diff --git a/third_party/aom/test/av1_highbd_iht_test.cc b/third_party/aom/test/av1_highbd_iht_test.cc index 7f077b657c..6d77cbf7ea 100644 --- a/third_party/aom/test/av1_highbd_iht_test.cc +++ b/third_party/aom/test/av1_highbd_iht_test.cc @@ -308,7 +308,8 @@ INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdInvTxfm2d, ::testing::Values(av1_highbd_inv_txfm_add_sse4_1)); #endif -#if HAVE_AVX2 +// TODO(http://crbug.com/aomedia/2350): these cause test vector mismatches. +#if 0 // HAVE_AVX2 INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdInvTxfm2d, ::testing::Values(av1_highbd_inv_txfm_add_avx2)); #endif diff --git a/third_party/aom/test/dr_prediction_test.cc b/third_party/aom/test/dr_prediction_test.cc index 603694f3ae..4be8489b7d 100644 --- a/third_party/aom/test/dr_prediction_test.cc +++ b/third_party/aom/test/dr_prediction_test.cc @@ -59,7 +59,9 @@ typedef void (*Z1_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh, template void z1_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh, const uint8_t *above, const uint8_t *left, int upsample_above, - int /*upsample_left*/, int dx, int dy, int /*bd*/) { + int upsample_left, int dx, int dy, int bd) { + (void)bd; + (void)upsample_left; fn(dst, stride, bw, bh, above, left, upsample_above, dx, dy); } @@ -69,7 +71,9 @@ typedef void (*Z2_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh, template void z2_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh, const uint8_t *above, const uint8_t *left, int upsample_above, - int upsample_left, int dx, int dy, int /*bd*/) { + int upsample_left, int dx, int dy, int bd) { + (void)bd; + (void)upsample_left; fn(dst, stride, bw, bh, above, left, upsample_above, upsample_left, dx, dy); } @@ -78,9 +82,10 @@ typedef void (*Z3_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh, int upsample_left, int dx, int dy); template void z3_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh, - const uint8_t *above, const uint8_t *left, - int /*upsample_above*/, int upsample_left, int dx, int dy, - int /*bd*/) { + const uint8_t *above, const uint8_t *left, int upsample_above, + int upsample_left, int dx, int dy, int bd) { + (void)bd; + (void)upsample_above; fn(dst, stride, bw, bh, above, left, upsample_left, dx, dy); } @@ -90,8 +95,10 @@ typedef void (*Z1_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh, template void z1_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, - int upsample_above, int /*upsample_left*/, int dx, int dy, + int upsample_above, int upsample_left, int dx, int dy, int bd) { + (void)bd; + (void)upsample_left; fn(dst, stride, bw, bh, above, left, upsample_above, dx, dy, bd); } @@ -104,6 +111,7 @@ void z2_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_above, int upsample_left, int dx, int dy, int bd) { + (void)bd; fn(dst, stride, bw, bh, above, left, upsample_above, upsample_left, dx, dy, bd); } @@ -114,8 +122,10 @@ typedef void (*Z3_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh, template void z3_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, - int /*upsample_above*/, int upsample_left, int dx, int dy, + int upsample_above, int upsample_left, int dx, int dy, int bd) { + (void)bd; + (void)upsample_above; fn(dst, stride, bw, bh, above, left, upsample_left, dx, dy, bd); } @@ -172,6 +182,9 @@ class DrPredTest : public ::testing::TestWithParam > { const int kNumTests = speedtest ? kMaxNumTests : 1; aom_usec_timer timer; int tst_time = 0; + + bd_ = params_.bit_depth; + aom_usec_timer_start(&timer); for (int k = 0; k < kNumTests; ++k) { params_.ref_fn(dst_ref_, dst_stride_, bw_, bh_, above_, left_, @@ -199,6 +212,8 @@ class DrPredTest : public ::testing::TestWithParam > { } void RunTest(bool speedtest, bool needsaturation, int p_angle) { + bd_ = params_.bit_depth; + if (needsaturation) { for (int i = 0; i < kBufSize; ++i) { above_data_[i] = left_data_[i] = (1 << bd_) - 1; @@ -350,9 +365,11 @@ INSTANTIATE_TEST_CASE_P( ::testing::Values(DrPredFunc(&z1_wrapper, &z1_wrapper, AOM_BITS_8, kZ1Start), + /* TODO(niva213@gmail.com): Re-enable this test after + fixing valgrind issue: https://crbug.com/aomedia/2316 DrPredFunc(&z2_wrapper, &z2_wrapper, - AOM_BITS_8, kZ2Start), + AOM_BITS_8, kZ2Start), */ DrPredFunc(&z3_wrapper, &z3_wrapper, AOM_BITS_8, kZ3Start))); @@ -397,7 +414,8 @@ INSTANTIATE_TEST_CASE_P( &z1_wrapper_hbd, &z1_wrapper_hbd, AOM_BITS_12, kZ1Start), - /* TODO(https://crbug.com/aomedia/2288) + /* TODO(niva213@gmail.com): Re-enable these tests after + fixing valgrind issue: https://crbug.com/aomedia/2316 DrPredFunc( &z2_wrapper_hbd, &z2_wrapper_hbd, @@ -409,8 +427,7 @@ INSTANTIATE_TEST_CASE_P( DrPredFunc( &z2_wrapper_hbd, &z2_wrapper_hbd, - AOM_BITS_12, kZ2Start), - */ + AOM_BITS_12, kZ2Start),*/ DrPredFunc( &z3_wrapper_hbd, &z3_wrapper_hbd, diff --git a/third_party/aom/test/edge_detect_test.cc b/third_party/aom/test/edge_detect_test.cc index 47466cb872..77a731f0d5 100644 --- a/third_party/aom/test/edge_detect_test.cc +++ b/third_party/aom/test/edge_detect_test.cc @@ -185,8 +185,9 @@ TEST_P(EdgeDetectBrightnessTest, DetectUniformBrightness) { const bool high_bd = GET_PARAM(3); const int bd = GET_PARAM(4); - ASSERT_EQ(0, av1_edge_exists(input_, stride_8tap(width), width, height, - high_bd, bd)); + ASSERT_EQ( + 0, av1_edge_exists(input_, stride_8tap(width), width, height, high_bd, bd) + .magnitude); } INSTANTIATE_TEST_CASE_P(ImageBrightnessTests, EdgeDetectBrightnessTest, @@ -245,9 +246,11 @@ TEST_P(EdgeDetectImageTest, BlackWhite) { free(orig); // Value should be between 556 and 560. ASSERT_LE(556, av1_edge_exists(padded, stride_8tap(width), width, height, - high_bd, bd)); + high_bd, bd) + .magnitude); ASSERT_GE(560, av1_edge_exists(padded, stride_8tap(width), width, height, - high_bd, bd)); + high_bd, bd) + .magnitude); free_pad_8tap(padded, width, high_bd); } diff --git a/third_party/aom/test/encode_api_test.cc b/third_party/aom/test/encode_api_test.cc index c26f5720f2..235480a13c 100644 --- a/third_party/aom/test/encode_api_test.cc +++ b/third_party/aom/test/encode_api_test.cc @@ -50,7 +50,7 @@ TEST(EncodeAPI, InvalidParams) { EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, kCodecs[i], NULL, 0)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_enc_config_default(kCodecs[i], &cfg, 1)); + aom_codec_enc_config_default(kCodecs[i], &cfg, 2)); EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(kCodecs[i], &cfg, 0)); EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, kCodecs[i], &cfg, 0)); diff --git a/third_party/aom/test/error_block_test.cc b/third_party/aom/test/error_block_test.cc index 353947c3d7..3664ccf29f 100644 --- a/third_party/aom/test/error_block_test.cc +++ b/third_party/aom/test/error_block_test.cc @@ -156,6 +156,70 @@ TEST_P(ErrorBlockTest, ExtremeValues) { << "First failed at test case " << first_failure; } +TEST_P(ErrorBlockTest, DISABLED_Speed) { + ACMRandom rnd(ACMRandom::DeterministicSeed()); + DECLARE_ALIGNED(16, tran_low_t, coeff[4096]); + DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]); + intptr_t block_size; + int64_t ssz; + int num_iters = 100000; + int64_t ref_ssz; + int k; + const int msb = bit_depth_ + 8 - 1; + for (int i = 0; i < 9; ++i) { + block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64 + for (k = 0; k < 9; k++) { + for (int j = 0; j < block_size; j++) { + if (k < 5) { + if (rnd(2)) { + // Positive number + coeff[j] = rnd(1 << msb); + dqcoeff[j] = rnd(1 << msb); + } else { + // Negative number + coeff[j] = -rnd(1 << msb); + dqcoeff[j] = -rnd(1 << msb); + } + } else { + if (rnd(2)) { + // Positive number + coeff[j] = rnd(1 << 14); + dqcoeff[j] = rnd(1 << 14); + } else { + // Negative number + coeff[j] = -rnd(1 << 14); + dqcoeff[j] = -rnd(1 << 14); + } + } + } + aom_usec_timer ref_timer, test_timer; + + aom_usec_timer_start(&ref_timer); + for (int i = 0; i < num_iters; ++i) { + ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_); + } + aom_usec_timer_mark(&ref_timer); + const int elapsed_time_c = + static_cast(aom_usec_timer_elapsed(&ref_timer)); + + aom_usec_timer_start(&test_timer); + for (int i = 0; i < num_iters; ++i) { + error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_); + } + aom_usec_timer_mark(&test_timer); + + const int elapsed_time_simd = + static_cast(aom_usec_timer_elapsed(&test_timer)); + + printf( + " c_time=%d \t simd_time=%d \t " + "gain=%d \n", + elapsed_time_c, elapsed_time_simd, + (elapsed_time_c / elapsed_time_simd)); + } + } +} + #if (HAVE_SSE2 || HAVE_AVX) using ::testing::make_tuple; @@ -168,4 +232,17 @@ INSTANTIATE_TEST_CASE_P( make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c, AOM_BITS_8))); #endif // HAVE_SSE2 + +#if (HAVE_AVX2) +using ::testing::make_tuple; + +INSTANTIATE_TEST_CASE_P( + AVX2, ErrorBlockTest, + ::testing::Values(make_tuple(&av1_highbd_block_error_avx2, + &av1_highbd_block_error_c, AOM_BITS_10), + make_tuple(&av1_highbd_block_error_avx2, + &av1_highbd_block_error_c, AOM_BITS_12), + make_tuple(&av1_highbd_block_error_avx2, + &av1_highbd_block_error_c, AOM_BITS_8))); +#endif // HAVE_AVX2 } // namespace diff --git a/third_party/aom/test/fwd_kf_test.cc b/third_party/aom/test/fwd_kf_test.cc new file mode 100644 index 0000000000..6c428d98db --- /dev/null +++ b/third_party/aom/test/fwd_kf_test.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019, 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/i420_video_source.h" +#include "test/util.h" + +namespace { + +typedef struct { + const int max_kf_dist; + const double psnr_thresh; +} FwdKfTestParam; + +const FwdKfTestParam kTestParams[] = { + { 4, 37.3 }, { 6, 36.5 }, { 8, 35.8 }, + { 12, 34.3 }, { 16, 34.3 }, { 18, 33.7 } +}; + +// Params: encoding mode and index into the kMaxKfDists array to control +// kf-max-dist +class ForwardKeyTest + : public ::libaom_test::CodecTestWith2Params, + public ::libaom_test::EncoderTest { + protected: + ForwardKeyTest() + : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), + kf_max_dist_ind_(GET_PARAM(2)) {} + virtual ~ForwardKeyTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(encoding_mode_); + const aom_rational timebase = { 1, 30 }; + cfg_.g_timebase = timebase; + cpu_used_ = 2; + kf_max_dist_ = kTestParams[kf_max_dist_ind_].max_kf_dist; + psnr_threshold_ = kTestParams[kf_max_dist_ind_].psnr_thresh; + cfg_.rc_end_usage = AOM_VBR; + cfg_.rc_target_bitrate = 200; + cfg_.g_lag_in_frames = 10; + cfg_.fwd_kf_enabled = 1; + cfg_.kf_max_dist = kf_max_dist_; + cfg_.g_threads = 0; + init_flags_ = AOM_CODEC_USE_PSNR; + } + + virtual void BeginPassHook(unsigned int) { + psnr_ = 0.0; + nframes_ = 0; + } + + virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) { + psnr_ += pkt->data.psnr.psnr[0]; + nframes_++; + } + + virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) { + if (video->frame() == 0) { + encoder->Control(AOME_SET_CPUUSED, cpu_used_); + 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); + } + } + } + + double GetAveragePsnr() const { + if (nframes_) return psnr_ / nframes_; + return 0.0; + } + + double GetPsnrThreshold() { return psnr_threshold_; } + + ::libaom_test::TestMode encoding_mode_; + const int kf_max_dist_ind_; + double psnr_threshold_; + int kf_max_dist_; + int cpu_used_; + int nframes_; + double psnr_; +}; + +TEST_P(ForwardKeyTest, ForwardKeyEncodeTest) { + libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + cfg_.g_timebase.den, cfg_.g_timebase.num, + 0, 20); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + // TODO(sarahparker) Add functionality to assert the minimum number of + // keyframes were placed. + EXPECT_GT(GetAveragePsnr(), GetPsnrThreshold()) + << "kf max dist = " << kf_max_dist_; +} + +AV1_INSTANTIATE_TEST_CASE( + ForwardKeyTest, ::testing::Values(::libaom_test::kTwoPassGood), + ::testing::Range(0, static_cast(GTEST_ARRAY_SIZE_(kTestParams)))); +} // namespace diff --git a/third_party/aom/test/gf_max_pyr_height_test.cc b/third_party/aom/test/gf_max_pyr_height_test.cc new file mode 100644 index 0000000000..2d78493302 --- /dev/null +++ b/third_party/aom/test/gf_max_pyr_height_test.cc @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019, 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/i420_video_source.h" +#include "test/util.h" + +namespace { + +static const struct GFMaxPyrHeightTestParam { + int gf_max_pyr_height; + double psnr_thresh; +} kTestParams[] = { + { 0, 34.75 }, { 1, 34.75 }, { 2, 35.25 }, { 3, 35.50 }, { 4, 35.50 }, +}; + +// Compiler may decide to add some padding to the struct above for alignment, +// which the gtest may try to print (on error for example). This would cause +// valgrind to complain that the padding is uninitialized. To avoid that, we +// provide our own function to print the struct. +// This also makes '--gtest_list_tests' output more understandable. +std::ostream &operator<<(std::ostream &os, const GFMaxPyrHeightTestParam &p) { + os << "GFMaxPyrHeightTestParam { " + << "gf_max_pyr_height = " << p.gf_max_pyr_height << ", " + << "psnr_thresh = " << p.psnr_thresh << " }"; + return os; +} + +// Params: encoding mode and GFMaxPyrHeightTestParam object. +class GFMaxPyrHeightTest + : public ::libaom_test::CodecTestWith2Params, + public ::libaom_test::EncoderTest { + protected: + GFMaxPyrHeightTest() + : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)) { + gf_max_pyr_height_ = GET_PARAM(2).gf_max_pyr_height; + psnr_threshold_ = GET_PARAM(2).psnr_thresh; + } + virtual ~GFMaxPyrHeightTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(encoding_mode_); + const aom_rational timebase = { 1, 30 }; + cfg_.g_timebase = timebase; + cpu_used_ = 4; + cfg_.rc_end_usage = AOM_VBR; + cfg_.rc_target_bitrate = 200; + cfg_.g_lag_in_frames = 19; + cfg_.g_threads = 0; + init_flags_ = AOM_CODEC_USE_PSNR; + } + + virtual void BeginPassHook(unsigned int) { + psnr_ = 0.0; + nframes_ = 0; + } + + virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) { + psnr_ += pkt->data.psnr.psnr[0]; + nframes_++; + } + + virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) { + if (video->frame() == 0) { + encoder->Control(AOME_SET_CPUUSED, cpu_used_); + 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); + } + encoder->Control(AV1E_SET_GF_MAX_PYRAMID_HEIGHT, gf_max_pyr_height_); + } + } + + double GetAveragePsnr() const { + if (nframes_) return psnr_ / nframes_; + return 0.0; + } + + double GetPsnrThreshold() { return psnr_threshold_; } + + ::libaom_test::TestMode encoding_mode_; + double psnr_threshold_; + int gf_max_pyr_height_; + int cpu_used_; + int nframes_; + double psnr_; +}; + +TEST_P(GFMaxPyrHeightTest, EncodeAndVerifyPSNR) { + libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + cfg_.g_timebase.den, cfg_.g_timebase.num, + 0, 32); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + EXPECT_GT(GetAveragePsnr(), GetPsnrThreshold()) + << "GF Max Pyramid Height = " << gf_max_pyr_height_; +} + +AV1_INSTANTIATE_TEST_CASE(GFMaxPyrHeightTest, + ::testing::Values(::libaom_test::kTwoPassGood), + ::testing::ValuesIn(kTestParams)); +} // namespace diff --git a/third_party/aom/test/hiprec_convolve_test_util.cc b/third_party/aom/test/hiprec_convolve_test_util.cc index f5bf56e907..2672bcec3d 100644 --- a/third_party/aom/test/hiprec_convolve_test_util.cc +++ b/third_party/aom/test/hiprec_convolve_test_util.cc @@ -31,7 +31,7 @@ static void generate_kernels(ACMRandom *rnd, InterpKernel hkernel, hkernel[2] = hkernel[4] = WIENER_FILT_TAP2_MINV + rnd->PseudoUniform(WIENER_FILT_TAP2_MAXV + 1 - WIENER_FILT_TAP2_MINV); - hkernel[3] = -2 * (hkernel[0] + hkernel[1] + hkernel[2]); + hkernel[3] = -(hkernel[0] + hkernel[1] + hkernel[2]); hkernel[7] = 0; vkernel[0] = vkernel[6] = @@ -43,7 +43,7 @@ static void generate_kernels(ACMRandom *rnd, InterpKernel hkernel, vkernel[2] = vkernel[4] = WIENER_FILT_TAP2_MINV + rnd->PseudoUniform(WIENER_FILT_TAP2_MAXV + 1 - WIENER_FILT_TAP2_MINV); - vkernel[3] = -2 * (vkernel[0] + vkernel[1] + vkernel[2]); + vkernel[3] = -(vkernel[0] + vkernel[1] + vkernel[2]); vkernel[7] = 0; } diff --git a/third_party/aom/test/horz_superres_test.cc b/third_party/aom/test/horz_superres_test.cc index 1627684b9e..f2c2115744 100644 --- a/third_party/aom/test/horz_superres_test.cc +++ b/third_party/aom/test/horz_superres_test.cc @@ -28,13 +28,8 @@ using ::testing::tuple; /* TESTING PARAMETERS */ -#define NUM_TEST_VIDEOS 3 - const int kBitrate = 40; -// PSNR thresholds found by experiment -const double kPSNRThresholds[] = { 26.0, 28.0, 20.0 }; - typedef struct { const char *filename; aom_img_fmt fmt; @@ -42,18 +37,20 @@ typedef struct { unsigned int profile; unsigned int limit; unsigned int screen_content; + double psnr_threshold; } TestVideoParam; const TestVideoParam kTestVideoVectors[] = { - { "park_joy_90p_8_420.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 5, 0 }, - { "park_joy_90p_10_444.y4m", AOM_IMG_FMT_I44416, AOM_BITS_10, 1, 5, 0 }, - { "screendata.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 4, 1 }, + { "park_joy_90p_8_420.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 5, 0, 26.0 }, + { "park_joy_90p_10_444.y4m", AOM_IMG_FMT_I44416, AOM_BITS_10, 1, 5, 0, 28.0 }, + { "screendata.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 4, 1, 20.0 }, + // Image coding (single frame). + { "niklas_1280_720_30.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 1, 0, 32.0 }, }; -// Superres modes tested -// SUPERRES_QTHRESH is not included, as it has its own test -const SUPERRES_MODE kSuperresModesNotQThresh[] = { SUPERRES_FIXED, - SUPERRES_RANDOM }; +// Modes with extra params have their own tests. +const SUPERRES_MODE kSuperresModesWithoutParams[] = { SUPERRES_RANDOM, + SUPERRES_AUTO }; // Superres denominators and superres kf denominators to be tested typedef tuple SuperresDenominatorPair; @@ -74,10 +71,8 @@ const SuperresQThresholdPair kSuperresQThresholds[] = { /* END (TESTING PARAMETERS) */ // Test parameter list: -// <[needed for EncoderTest], test_video_idx_, superres_mode_, -// tuple(superres_denom_, superres_kf_denom_)> -typedef tuple +// <[needed for EncoderTest], test_video_param_, superres_mode_> +typedef tuple HorzSuperresTestParam; class HorzSuperresEndToEndTest @@ -85,16 +80,113 @@ class HorzSuperresEndToEndTest public ::libaom_test::EncoderTest { protected: HorzSuperresEndToEndTest() - : EncoderTest(GET_PARAM(0)), test_video_idx_(GET_PARAM(1)), - superres_mode_(GET_PARAM(2)), psnr_(0.0), frame_count_(0) { - test_video_param_ = kTestVideoVectors[test_video_idx_]; + : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)), + superres_mode_(GET_PARAM(2)), psnr_(0.0), frame_count_(0) {} - SuperresDenominatorPair denoms = GET_PARAM(3); + virtual ~HorzSuperresEndToEndTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(::libaom_test::kTwoPassGood); + cfg_.g_lag_in_frames = 5; + cfg_.rc_end_usage = AOM_Q; + cfg_.rc_target_bitrate = kBitrate; + cfg_.g_error_resilient = 0; + cfg_.g_profile = test_video_param_.profile; + cfg_.g_input_bit_depth = (unsigned int)test_video_param_.bit_depth; + cfg_.g_bit_depth = test_video_param_.bit_depth; + init_flags_ = AOM_CODEC_USE_PSNR; + if (cfg_.g_bit_depth > 8) init_flags_ |= AOM_CODEC_USE_HIGHBITDEPTH; + + // Set superres parameters + cfg_.rc_superres_mode = superres_mode_; + } + + virtual void BeginPassHook(unsigned int) { + psnr_ = 0.0; + frame_count_ = 0; + } + + virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) { + psnr_ += pkt->data.psnr.psnr[0]; + frame_count_++; + } + + virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) { + if (video->frame() == 0) { + encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1); + encoder->Control(AV1E_SET_TILE_COLUMNS, 4); + + // Set cpu-used = 8 for speed + encoder->Control(AOME_SET_CPUUSED, 8); + + // Test screen coding tools + if (test_video_param_.screen_content) + encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN); + else + encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT); + + encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1); + encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7); + encoder->Control(AOME_SET_ARNR_STRENGTH, 5); + } + } + + double GetAveragePsnr() const { + if (frame_count_) return psnr_ / frame_count_; + return 0.0; + } + + void DoTest() { + std::unique_ptr video; + video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0, + test_video_param_.limit)); + ASSERT_TRUE(video.get() != NULL); + + ASSERT_NO_FATAL_FAILURE(RunLoop(video.get())); + const double psnr = GetAveragePsnr(); + EXPECT_GT(psnr, test_video_param_.psnr_threshold) + << "superres_mode_ = " << superres_mode_; + + EXPECT_EQ(test_video_param_.limit, frame_count_) + << "superres_mode_ = " << superres_mode_; + } + + TestVideoParam test_video_param_; + SUPERRES_MODE superres_mode_; + + private: + double psnr_; + unsigned int frame_count_; +}; + +TEST_P(HorzSuperresEndToEndTest, HorzSuperresEndToEndPSNRTest) { DoTest(); } + +AV1_INSTANTIATE_TEST_CASE(HorzSuperresEndToEndTest, + ::testing::ValuesIn(kTestVideoVectors), + ::testing::ValuesIn(kSuperresModesWithoutParams)); + +// Test parameter list: +// <[needed for EncoderTest], test_video_param_, tuple(superres_denom_, +// superres_kf_denom_)> +typedef tuple + HorzSuperresFixedTestParam; + +class HorzSuperresFixedEndToEndTest + : public ::testing::TestWithParam, + public ::libaom_test::EncoderTest { + protected: + HorzSuperresFixedEndToEndTest() + : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)), + superres_mode_(SUPERRES_FIXED), psnr_(0.0), frame_count_(0) { + SuperresDenominatorPair denoms = GET_PARAM(2); superres_denom_ = ::testing::get<0>(denoms); superres_kf_denom_ = ::testing::get<1>(denoms); } - virtual ~HorzSuperresEndToEndTest() {} + virtual ~HorzSuperresFixedEndToEndTest() {} virtual void SetUp() { InitializeConfig(); @@ -151,8 +243,6 @@ class HorzSuperresEndToEndTest return 0.0; } - double GetPsnrThreshold() { return kPSNRThresholds[test_video_idx_]; } - void DoTest() { std::unique_ptr video; video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0, @@ -161,7 +251,7 @@ class HorzSuperresEndToEndTest ASSERT_NO_FATAL_FAILURE(RunLoop(video.get())); const double psnr = GetAveragePsnr(); - EXPECT_GT(psnr, GetPsnrThreshold()) + EXPECT_GT(psnr, test_video_param_.psnr_threshold) << "superres_mode_ = " << superres_mode_ << ", superres_denom_ = " << superres_denom_ << ", superres_kf_denom_ = " << superres_kf_denom_; @@ -172,7 +262,6 @@ class HorzSuperresEndToEndTest << ", superres_kf_denom_ = " << superres_kf_denom_; } - int test_video_idx_; TestVideoParam test_video_param_; SUPERRES_MODE superres_mode_; int superres_denom_; @@ -183,17 +272,16 @@ class HorzSuperresEndToEndTest unsigned int frame_count_; }; -TEST_P(HorzSuperresEndToEndTest, HorzSuperresEndToEndPSNRTest) { DoTest(); } +TEST_P(HorzSuperresFixedEndToEndTest, HorzSuperresFixedTestParam) { DoTest(); } -AV1_INSTANTIATE_TEST_CASE(HorzSuperresEndToEndTest, - ::testing::Range(0, NUM_TEST_VIDEOS), - ::testing::ValuesIn(kSuperresModesNotQThresh), +AV1_INSTANTIATE_TEST_CASE(HorzSuperresFixedEndToEndTest, + ::testing::ValuesIn(kTestVideoVectors), ::testing::ValuesIn(kSuperresDenominators)); // Test parameter list: -// <[needed for EncoderTest], test_video_idx_, tuple(superres_denom_, -// superres_kf_denom_), tuple(superres_qthresh_,superres_kf_qthresh_)> -typedef tuple +typedef tuple HorzSuperresQThreshTestParam; @@ -202,15 +290,9 @@ class HorzSuperresQThreshEndToEndTest public ::libaom_test::EncoderTest { protected: HorzSuperresQThreshEndToEndTest() - : EncoderTest(GET_PARAM(0)), test_video_idx_(GET_PARAM(1)), + : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)), superres_mode_(SUPERRES_QTHRESH), psnr_(0.0), frame_count_(0) { - test_video_param_ = kTestVideoVectors[test_video_idx_]; - - SuperresDenominatorPair denoms = GET_PARAM(2); - superres_denom_ = ::testing::get<0>(denoms); - superres_kf_denom_ = ::testing::get<1>(denoms); - - SuperresQThresholdPair qthresholds = GET_PARAM(3); + SuperresQThresholdPair qthresholds = GET_PARAM(2); superres_qthresh_ = ::testing::get<0>(qthresholds); superres_kf_qthresh_ = ::testing::get<1>(qthresholds); } @@ -232,8 +314,6 @@ class HorzSuperresQThreshEndToEndTest // Set superres parameters cfg_.rc_superres_mode = superres_mode_; - cfg_.rc_superres_denominator = superres_denom_; - cfg_.rc_superres_kf_denominator = superres_kf_denom_; cfg_.rc_superres_qthresh = superres_qthresh_; cfg_.rc_superres_kf_qthresh = superres_kf_qthresh_; } @@ -274,8 +354,6 @@ class HorzSuperresQThreshEndToEndTest return 0.0; } - double GetPsnrThreshold() { return kPSNRThresholds[test_video_idx_]; } - void DoTest() { std::unique_ptr video; video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0, @@ -284,26 +362,19 @@ class HorzSuperresQThreshEndToEndTest ASSERT_NO_FATAL_FAILURE(RunLoop(video.get())); const double psnr = GetAveragePsnr(); - EXPECT_GT(psnr, GetPsnrThreshold()) + EXPECT_GT(psnr, test_video_param_.psnr_threshold) << "superres_mode_ = " << superres_mode_ - << ", superres_denom_ = " << superres_denom_ - << ", superres_kf_denom_ = " << superres_kf_denom_ << ", superres_qthresh_ = " << superres_qthresh_ << ", superres_kf_qthresh_ = " << superres_kf_qthresh_; EXPECT_EQ(test_video_param_.limit, frame_count_) << "superres_mode_ = " << superres_mode_ - << ", superres_denom_ = " << superres_denom_ - << ", superres_kf_denom_ = " << superres_kf_denom_ << ", superres_qthresh_ = " << superres_qthresh_ << ", superres_kf_qthresh_ = " << superres_kf_qthresh_; } - int test_video_idx_; TestVideoParam test_video_param_; SUPERRES_MODE superres_mode_; - int superres_denom_; - int superres_kf_denom_; int superres_qthresh_; int superres_kf_qthresh_; @@ -317,8 +388,7 @@ TEST_P(HorzSuperresQThreshEndToEndTest, HorzSuperresQThreshEndToEndPSNRTest) { } AV1_INSTANTIATE_TEST_CASE(HorzSuperresQThreshEndToEndTest, - ::testing::Range(0, NUM_TEST_VIDEOS), - ::testing::ValuesIn(kSuperresDenominators), + ::testing::ValuesIn(kTestVideoVectors), ::testing::ValuesIn(kSuperresQThresholds)); } // namespace diff --git a/third_party/aom/test/level_test.cc b/third_party/aom/test/level_test.cc new file mode 100644 index 0000000000..e3b0ef18ca --- /dev/null +++ b/third_party/aom/test/level_test.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019, 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 + +#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/y4m_video_source.h" +#include "test/yuv_video_source.h" + +namespace { +// Speed settings tested +static const int kCpuUsedVectors[] = { + 1, + 2, + 3, + 4, +}; + +class LevelTest + : public ::libaom_test::CodecTestWith2Params, + public ::libaom_test::EncoderTest { + protected: + LevelTest() + : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), + cpu_used_(GET_PARAM(2)), target_level_(31) {} + + virtual ~LevelTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(encoding_mode_); + if (encoding_mode_ != ::libaom_test::kRealTime) { + cfg_.g_lag_in_frames = 5; + 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() == 0) { + encoder->Control(AOME_SET_CPUUSED, cpu_used_); + encoder->Control(AV1E_SET_TARGET_SEQ_LEVEL_IDX, target_level_); + 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 target_level_; +}; + +TEST_P(LevelTest, TestTargetLevelApi) { + static const aom_codec_iface_t *codec = &aom_codec_av1_cx_algo; + aom_codec_ctx_t enc; + aom_codec_enc_cfg_t cfg; + EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(codec, &cfg, 0)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, codec, &cfg, 0)); + for (int operating_point = 0; operating_point <= 32; ++operating_point) { + for (int level = 0; level <= 32; ++level) { + const int target_level = operating_point * 100 + level; + if ((level >= 0 && level <= 23) || level == 31 || operating_point > 31) { + EXPECT_EQ(AOM_CODEC_OK, + aom_codec_control(&enc, AV1E_SET_TARGET_SEQ_LEVEL_IDX, + target_level)); + } else { + EXPECT_EQ(AOM_CODEC_INVALID_PARAM, + aom_codec_control(&enc, AV1E_SET_TARGET_SEQ_LEVEL_IDX, + target_level)); + } + } + } + EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); +} + +TEST_P(LevelTest, TestTargetLevel19) { + std::unique_ptr video; + video.reset(new libaom_test::Y4mVideoSource("park_joy_90p_8_420.y4m", 0, 10)); + ASSERT_TRUE(video.get() != NULL); + // Level index 19 corresponding to level 6.3. + target_level_ = 19; + ASSERT_NO_FATAL_FAILURE(RunLoop(video.get())); +} + +AV1_INSTANTIATE_TEST_CASE(LevelTest, + ::testing::Values(::libaom_test::kTwoPassGood), + ::testing::ValuesIn(kCpuUsedVectors)); +} // namespace diff --git a/third_party/aom/test/quantize_func_test.cc b/third_party/aom/test/quantize_func_test.cc index 2975c1dff5..067a981825 100644 --- a/third_party/aom/test/quantize_func_test.cc +++ b/third_party/aom/test/quantize_func_test.cc @@ -191,6 +191,13 @@ class QuantizeTest : public ::testing::TestWithParam { } } + void FillCoeffRandomRows(int num) { + FillCoeffZero(); + for (int i = 0; i < num; ++i) { + coeff_[i] = GetRandomCoeff(); + } + } + void FillCoeffZero() { FillCoeff(0); } void FillCoeffConstant() { @@ -287,28 +294,31 @@ TEST_P(QuantizeTest, DISABLED_Speed) { const int16_t *dequant = qtab_->dequant.y_dequant_QTX[q]; const int kNumTests = 5000000; aom_usec_timer timer, simd_timer; + int rows = tx_size_high[tx_size_]; + int cols = tx_size_wide[tx_size_]; + for (int cnt = 0; cnt <= rows; cnt++) { + FillCoeffRandomRows(cnt * cols); - FillCoeffRandom(); + aom_usec_timer_start(&timer); + for (int n = 0; n < kNumTests; ++n) { + quant_ref_(coeff_ptr, n_coeffs, zbin, round_fp, quant_fp, quant_shift, + qcoeff, dqcoeff, dequant, eob, sc->scan, sc->iscan); + } + aom_usec_timer_mark(&timer); - aom_usec_timer_start(&timer); - for (int n = 0; n < kNumTests; ++n) { - quant_ref_(coeff_ptr, n_coeffs, zbin, round_fp, quant_fp, quant_shift, - qcoeff, dqcoeff, dequant, eob, sc->scan, sc->iscan); + aom_usec_timer_start(&simd_timer); + for (int n = 0; n < kNumTests; ++n) { + quant_(coeff_ptr, n_coeffs, zbin, round_fp, quant_fp, quant_shift, qcoeff, + dqcoeff, dequant, eob, sc->scan, sc->iscan); + } + aom_usec_timer_mark(&simd_timer); + + const int elapsed_time = static_cast(aom_usec_timer_elapsed(&timer)); + const int simd_elapsed_time = + static_cast(aom_usec_timer_elapsed(&simd_timer)); + printf("c_time = %d \t simd_time = %d \t Gain = %d \n", elapsed_time, + simd_elapsed_time, (elapsed_time / simd_elapsed_time)); } - aom_usec_timer_mark(&timer); - - aom_usec_timer_start(&simd_timer); - for (int n = 0; n < kNumTests; ++n) { - quant_(coeff_ptr, n_coeffs, zbin, round_fp, quant_fp, quant_shift, qcoeff, - dqcoeff, dequant, eob, sc->scan, sc->iscan); - } - aom_usec_timer_mark(&simd_timer); - - const int elapsed_time = static_cast(aom_usec_timer_elapsed(&timer)); - const int simd_elapsed_time = - static_cast(aom_usec_timer_elapsed(&simd_timer)); - printf("c_time = %d \t simd_time = %d \t Gain = %d \n", elapsed_time, - simd_elapsed_time, (elapsed_time / simd_elapsed_time)); } using ::testing::make_tuple; @@ -398,6 +408,24 @@ const QuantizeParam kQParamArraySSE2[] = { TX_32X32, TYPE_B, AOM_BITS_10), make_tuple(&aom_highbd_quantize_b_32x32_c, &aom_highbd_quantize_b_32x32_sse2, TX_32X32, TYPE_B, AOM_BITS_12), + make_tuple(&aom_highbd_quantize_b_64x64_c, &aom_highbd_quantize_b_64x64_sse2, + TX_64X64, TYPE_B, AOM_BITS_8), + make_tuple(&aom_highbd_quantize_b_64x64_c, &aom_highbd_quantize_b_64x64_sse2, + TX_64X64, TYPE_B, AOM_BITS_10), + make_tuple(&aom_highbd_quantize_b_64x64_c, &aom_highbd_quantize_b_64x64_sse2, + TX_64X64, TYPE_B, AOM_BITS_12), + make_tuple(&aom_quantize_b_adaptive_c, &aom_quantize_b_adaptive_sse2, + TX_16X16, TYPE_B, AOM_BITS_8), + make_tuple(&aom_quantize_b_adaptive_c, &aom_quantize_b_adaptive_sse2, TX_8X8, + TYPE_B, AOM_BITS_8), + make_tuple(&aom_quantize_b_adaptive_c, &aom_quantize_b_adaptive_sse2, TX_4X4, + TYPE_B, AOM_BITS_8), + make_tuple(&aom_quantize_b_32x32_adaptive_c, + &aom_quantize_b_32x32_adaptive_sse2, TX_32X16, TYPE_B, AOM_BITS_8), + make_tuple(&aom_quantize_b_32x32_adaptive_c, + &aom_quantize_b_32x32_adaptive_sse2, TX_16X32, TYPE_B, AOM_BITS_8), + make_tuple(&aom_quantize_b_32x32_adaptive_c, + &aom_quantize_b_32x32_adaptive_sse2, TX_32X32, TYPE_B, AOM_BITS_8) }; INSTANTIATE_TEST_CASE_P(SSE2, QuantizeTest, diff --git a/third_party/aom/test/resize_test.cc b/third_party/aom/test/resize_test.cc index 34964f0a30..39e7d1bd5e 100644 --- a/third_party/aom/test/resize_test.cc +++ b/third_party/aom/test/resize_test.cc @@ -374,6 +374,7 @@ class ResizeRealtimeTest if (video->frame() == 0) { encoder->Control(AV1E_SET_AQ_MODE, 3); encoder->Control(AOME_SET_CPUUSED, set_cpu_used_); + encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1); } if (change_bitrate_ && video->frame() == 120) { diff --git a/third_party/aom/test/rt_end_to_end_test.cc b/third_party/aom/test/rt_end_to_end_test.cc new file mode 100644 index 0000000000..9c3e96b905 --- /dev/null +++ b/third_party/aom/test/rt_end_to_end_test.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2019, 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 + +#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/y4m_video_source.h" +#include "test/yuv_video_source.h" + +namespace { + +const unsigned int kFrames = 10; +const int kBitrate = 500; + +// List of psnr thresholds for speed settings 0-8 +const double kPsnrThreshold[9] = { 36.9, 36.9, 36.85, 36.8, 36.6, + 36.4, 36.0, 35.5, 35.0 }; + +typedef struct { + const char *filename; + unsigned int input_bit_depth; + aom_img_fmt fmt; + aom_bit_depth_t bit_depth; + unsigned int profile; +} TestVideoParam; + +std::ostream &operator<<(std::ostream &os, const TestVideoParam &test_arg) { + return os << "TestVideoParam { filename:" << test_arg.filename + << " input_bit_depth:" << test_arg.input_bit_depth + << " fmt:" << test_arg.fmt << " bit_depth:" << test_arg.bit_depth + << " profile:" << test_arg.profile << "}"; +} + +// TODO(kyslov): Add more test vectors +const TestVideoParam kTestVectors[] = { + { "park_joy_90p_8_420.y4m", 8, AOM_IMG_FMT_I420, AOM_BITS_8, 0 }, +}; + +// Speed settings tested +const int kCpuUsedVectors[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + +class RTEndToEndTest + : public ::libaom_test::CodecTestWith2Params, + public ::libaom_test::EncoderTest { + protected: + RTEndToEndTest() + : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)), + cpu_used_(GET_PARAM(2)), psnr_(0.0), nframes_(0) {} + + virtual ~RTEndToEndTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(::libaom_test::kRealTime); + + cfg_.g_usage = 1; // TODO(kyslov): Move it to encode_test_driver.cc + 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 BeginPassHook(unsigned int) { + psnr_ = 0.0; + nframes_ = 0; + } + + virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) { + psnr_ += pkt->data.psnr.psnr[0]; + nframes_++; + } + + virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) { + if (video->frame() == 0) { + encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1); + encoder->Control(AV1E_SET_TILE_COLUMNS, 1); + encoder->Control(AOME_SET_CPUUSED, cpu_used_); + encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT); + } + } + + double GetAveragePsnr() const { + if (nframes_) return psnr_ / nframes_; + return 0.0; + } + + double GetPsnrThreshold() { return kPsnrThreshold[cpu_used_]; } + + void DoTest() { + cfg_.rc_target_bitrate = kBitrate; + cfg_.g_error_resilient = 0; + cfg_.g_profile = test_video_param_.profile; + cfg_.g_input_bit_depth = test_video_param_.input_bit_depth; + cfg_.g_bit_depth = test_video_param_.bit_depth; + init_flags_ = AOM_CODEC_USE_PSNR; + if (cfg_.g_bit_depth > 8) init_flags_ |= AOM_CODEC_USE_HIGHBITDEPTH; + + std::unique_ptr video; + video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0, + kFrames)); + ASSERT_TRUE(video.get() != NULL); + + ASSERT_NO_FATAL_FAILURE(RunLoop(video.get())); + const double psnr = GetAveragePsnr(); + EXPECT_GT(psnr, GetPsnrThreshold()) << "cpu used = " << cpu_used_; + } + + TestVideoParam test_video_param_; + int cpu_used_; + + private: + double psnr_; + unsigned int nframes_; +}; + +class RTEndToEndTestLarge : public RTEndToEndTest {}; + +TEST_P(RTEndToEndTestLarge, EndtoEndPSNRTest) { DoTest(); } + +TEST_P(RTEndToEndTest, EndtoEndPSNRTest) { DoTest(); } + +AV1_INSTANTIATE_TEST_CASE(RTEndToEndTestLarge, + ::testing::ValuesIn(kTestVectors), + ::testing::ValuesIn(kCpuUsedVectors)); + +AV1_INSTANTIATE_TEST_CASE(RTEndToEndTest, ::testing::Values(kTestVectors[0]), + ::testing::Values(kCpuUsedVectors[8])); +} // namespace diff --git a/third_party/aom/test/test-data.sha1 b/third_party/aom/test/test-data.sha1 index 95342a8c38..bd6320634d 100644 --- a/third_party/aom/test/test-data.sha1 +++ b/third_party/aom/test/test-data.sha1 @@ -532,3 +532,9 @@ e94687eb0e90179b3800b6d5e11eb7e9bfb34eec *av1-1-b8-22-svc-L1T2.ivf 2bc12b16385ea14323bc79607fb8dfbd7edaf8ef *av1-1-b8-22-svc-L1T2.ivf.md5 32ef2f14ee9cb11a24a22934f4c065e926e5d236 *av1-1-b8-22-svc-L2T2.ivf f476a10ff06d750129f8229755d51e17ff141b2a *av1-1-b8-22-svc-L2T2.ivf.md5 +afca5502a489692b0a3c120370b0f43b8fc572a1 *av1-1-b8-04-cdfupdate.ivf +13b9423155a08d5e3a2fd9ae4a973bb046718cdf *av1-1-b8-04-cdfupdate.ivf.md5 +f064290d7fcd3b3de19020e8aec6c43c88d3a505 *av1-1-b8-05-mv.ivf +bff316e63ded5559116bdc2fa4aa97ad7b1a1761 *av1-1-b8-05-mv.ivf.md5 +b48a717c7c003b8dd23c3c2caed1ac673380fdb3 *av1-1-b8-06-mfmv.ivf +1424e3cb53e00eb56b94f4c725826274212c42b6 *av1-1-b8-06-mfmv.ivf.md5 diff --git a/third_party/aom/test/test.cmake b/third_party/aom/test/test.cmake index 1b11373c76..a44737a456 100644 --- a/third_party/aom/test/test.cmake +++ b/third_party/aom/test/test.cmake @@ -64,10 +64,14 @@ list(APPEND AOM_UNIT_TEST_ENCODER_SOURCES "${AOM_ROOT}/test/encode_test_driver.cc" "${AOM_ROOT}/test/encode_test_driver.h" "${AOM_ROOT}/test/end_to_end_test.cc" + "${AOM_ROOT}/test/fwd_kf_test.cc" + "${AOM_ROOT}/test/gf_max_pyr_height_test.cc" + "${AOM_ROOT}/test/rt_end_to_end_test.cc" "${AOM_ROOT}/test/error_resilience_test.cc" "${AOM_ROOT}/test/frame_size_tests.cc" "${AOM_ROOT}/test/horz_superres_test.cc" "${AOM_ROOT}/test/i420_video_source.h" + "${AOM_ROOT}/test/level_test.cc" "${AOM_ROOT}/test/lossless_test.cc" "${AOM_ROOT}/test/monochrome_test.cc" "${AOM_ROOT}/test/qm_test.cc" @@ -120,7 +124,8 @@ if(NOT BUILD_SHARED_LIBS) "${AOM_ROOT}/test/film_grain_table_test.cc" "${AOM_ROOT}/test/segment_binarization_sync.cc" "${AOM_ROOT}/test/superframe_test.cc" - "${AOM_ROOT}/test/tile_independence_test.cc") + "${AOM_ROOT}/test/tile_independence_test.cc" + "${AOM_ROOT}/test/yuv_temporal_filter_test.cc") endif() list(APPEND AOM_UNIT_TEST_COMMON_INTRIN_NEON diff --git a/third_party/aom/test/test_data_util.cmake b/third_party/aom/test/test_data_util.cmake index 6d684cbc27..c3c86aa770 100644 --- a/third_party/aom/test/test_data_util.cmake +++ b/third_party/aom/test/test_data_util.cmake @@ -500,6 +500,12 @@ if(CONFIG_AV1_DECODER) "av1-1-b8-03-sizeup.mkv.md5" "av1-1-b8-03-sizedown.mkv" "av1-1-b8-03-sizedown.mkv.md5" + "av1-1-b8-04-cdfupdate.ivf" + "av1-1-b8-04-cdfupdate.ivf.md5" + "av1-1-b8-05-mv.ivf" + "av1-1-b8-05-mv.ivf.md5" + "av1-1-b8-06-mfmv.ivf" + "av1-1-b8-06-mfmv.ivf.md5" "av1-1-b8-22-svc-L2T1.ivf" "av1-1-b8-22-svc-L2T1.ivf.md5" "av1-1-b8-22-svc-L1T2.ivf" diff --git a/third_party/aom/test/test_vectors.cc b/third_party/aom/test/test_vectors.cc index d2f333f74b..d2cd901b37 100644 --- a/third_party/aom/test/test_vectors.cc +++ b/third_party/aom/test/test_vectors.cc @@ -16,125 +16,243 @@ namespace libaom_test { #define NELEMENTS(x) static_cast(sizeof(x) / sizeof(x[0])) #if CONFIG_AV1_DECODER -const char *const kAV1TestVectors[] = { - "av1-1-b8-00-quantizer-00.ivf", "av1-1-b8-00-quantizer-01.ivf", - "av1-1-b8-00-quantizer-02.ivf", "av1-1-b8-00-quantizer-03.ivf", - "av1-1-b8-00-quantizer-04.ivf", "av1-1-b8-00-quantizer-05.ivf", - "av1-1-b8-00-quantizer-06.ivf", "av1-1-b8-00-quantizer-07.ivf", - "av1-1-b8-00-quantizer-08.ivf", "av1-1-b8-00-quantizer-09.ivf", - "av1-1-b8-00-quantizer-10.ivf", "av1-1-b8-00-quantizer-11.ivf", - "av1-1-b8-00-quantizer-12.ivf", "av1-1-b8-00-quantizer-13.ivf", - "av1-1-b8-00-quantizer-14.ivf", "av1-1-b8-00-quantizer-15.ivf", - "av1-1-b8-00-quantizer-16.ivf", "av1-1-b8-00-quantizer-17.ivf", - "av1-1-b8-00-quantizer-18.ivf", "av1-1-b8-00-quantizer-19.ivf", - "av1-1-b8-00-quantizer-20.ivf", "av1-1-b8-00-quantizer-21.ivf", - "av1-1-b8-00-quantizer-22.ivf", "av1-1-b8-00-quantizer-23.ivf", - "av1-1-b8-00-quantizer-24.ivf", "av1-1-b8-00-quantizer-25.ivf", - "av1-1-b8-00-quantizer-26.ivf", "av1-1-b8-00-quantizer-27.ivf", - "av1-1-b8-00-quantizer-28.ivf", "av1-1-b8-00-quantizer-29.ivf", - "av1-1-b8-00-quantizer-30.ivf", "av1-1-b8-00-quantizer-31.ivf", - "av1-1-b8-00-quantizer-32.ivf", "av1-1-b8-00-quantizer-33.ivf", - "av1-1-b8-00-quantizer-34.ivf", "av1-1-b8-00-quantizer-35.ivf", - "av1-1-b8-00-quantizer-36.ivf", "av1-1-b8-00-quantizer-37.ivf", - "av1-1-b8-00-quantizer-38.ivf", "av1-1-b8-00-quantizer-39.ivf", - "av1-1-b8-00-quantizer-40.ivf", "av1-1-b8-00-quantizer-41.ivf", - "av1-1-b8-00-quantizer-42.ivf", "av1-1-b8-00-quantizer-43.ivf", - "av1-1-b8-00-quantizer-44.ivf", "av1-1-b8-00-quantizer-45.ivf", - "av1-1-b8-00-quantizer-46.ivf", "av1-1-b8-00-quantizer-47.ivf", - "av1-1-b8-00-quantizer-48.ivf", "av1-1-b8-00-quantizer-49.ivf", - "av1-1-b8-00-quantizer-50.ivf", "av1-1-b8-00-quantizer-51.ivf", - "av1-1-b8-00-quantizer-52.ivf", "av1-1-b8-00-quantizer-53.ivf", - "av1-1-b8-00-quantizer-54.ivf", "av1-1-b8-00-quantizer-55.ivf", - "av1-1-b8-00-quantizer-56.ivf", "av1-1-b8-00-quantizer-57.ivf", - "av1-1-b8-00-quantizer-58.ivf", "av1-1-b8-00-quantizer-59.ivf", - "av1-1-b8-00-quantizer-60.ivf", "av1-1-b8-00-quantizer-61.ivf", - "av1-1-b8-00-quantizer-62.ivf", "av1-1-b8-00-quantizer-63.ivf", - "av1-1-b10-00-quantizer-00.ivf", "av1-1-b10-00-quantizer-01.ivf", - "av1-1-b10-00-quantizer-02.ivf", "av1-1-b10-00-quantizer-03.ivf", - "av1-1-b10-00-quantizer-04.ivf", "av1-1-b10-00-quantizer-05.ivf", - "av1-1-b10-00-quantizer-06.ivf", "av1-1-b10-00-quantizer-07.ivf", - "av1-1-b10-00-quantizer-08.ivf", "av1-1-b10-00-quantizer-09.ivf", - "av1-1-b10-00-quantizer-10.ivf", "av1-1-b10-00-quantizer-11.ivf", - "av1-1-b10-00-quantizer-12.ivf", "av1-1-b10-00-quantizer-13.ivf", - "av1-1-b10-00-quantizer-14.ivf", "av1-1-b10-00-quantizer-15.ivf", - "av1-1-b10-00-quantizer-16.ivf", "av1-1-b10-00-quantizer-17.ivf", - "av1-1-b10-00-quantizer-18.ivf", "av1-1-b10-00-quantizer-19.ivf", - "av1-1-b10-00-quantizer-20.ivf", "av1-1-b10-00-quantizer-21.ivf", - "av1-1-b10-00-quantizer-22.ivf", "av1-1-b10-00-quantizer-23.ivf", - "av1-1-b10-00-quantizer-24.ivf", "av1-1-b10-00-quantizer-25.ivf", - "av1-1-b10-00-quantizer-26.ivf", "av1-1-b10-00-quantizer-27.ivf", - "av1-1-b10-00-quantizer-28.ivf", "av1-1-b10-00-quantizer-29.ivf", - "av1-1-b10-00-quantizer-30.ivf", "av1-1-b10-00-quantizer-31.ivf", - "av1-1-b10-00-quantizer-32.ivf", "av1-1-b10-00-quantizer-33.ivf", - "av1-1-b10-00-quantizer-34.ivf", "av1-1-b10-00-quantizer-35.ivf", - "av1-1-b10-00-quantizer-36.ivf", "av1-1-b10-00-quantizer-37.ivf", - "av1-1-b10-00-quantizer-38.ivf", "av1-1-b10-00-quantizer-39.ivf", - "av1-1-b10-00-quantizer-40.ivf", "av1-1-b10-00-quantizer-41.ivf", - "av1-1-b10-00-quantizer-42.ivf", "av1-1-b10-00-quantizer-43.ivf", - "av1-1-b10-00-quantizer-44.ivf", "av1-1-b10-00-quantizer-45.ivf", - "av1-1-b10-00-quantizer-46.ivf", "av1-1-b10-00-quantizer-47.ivf", - "av1-1-b10-00-quantizer-48.ivf", "av1-1-b10-00-quantizer-49.ivf", - "av1-1-b10-00-quantizer-50.ivf", "av1-1-b10-00-quantizer-51.ivf", - "av1-1-b10-00-quantizer-52.ivf", "av1-1-b10-00-quantizer-53.ivf", - "av1-1-b10-00-quantizer-54.ivf", "av1-1-b10-00-quantizer-55.ivf", - "av1-1-b10-00-quantizer-56.ivf", "av1-1-b10-00-quantizer-57.ivf", - "av1-1-b10-00-quantizer-58.ivf", "av1-1-b10-00-quantizer-59.ivf", - "av1-1-b10-00-quantizer-60.ivf", "av1-1-b10-00-quantizer-61.ivf", - "av1-1-b10-00-quantizer-62.ivf", "av1-1-b10-00-quantizer-63.ivf", - "av1-1-b8-01-size-16x16.ivf", "av1-1-b8-01-size-16x18.ivf", - "av1-1-b8-01-size-16x32.ivf", "av1-1-b8-01-size-16x34.ivf", - "av1-1-b8-01-size-16x64.ivf", "av1-1-b8-01-size-16x66.ivf", - "av1-1-b8-01-size-18x16.ivf", "av1-1-b8-01-size-18x18.ivf", - "av1-1-b8-01-size-18x32.ivf", "av1-1-b8-01-size-18x34.ivf", - "av1-1-b8-01-size-18x64.ivf", "av1-1-b8-01-size-18x66.ivf", - "av1-1-b8-01-size-196x196.ivf", "av1-1-b8-01-size-196x198.ivf", - "av1-1-b8-01-size-196x200.ivf", "av1-1-b8-01-size-196x202.ivf", - "av1-1-b8-01-size-196x208.ivf", "av1-1-b8-01-size-196x210.ivf", - "av1-1-b8-01-size-196x224.ivf", "av1-1-b8-01-size-196x226.ivf", - "av1-1-b8-01-size-198x196.ivf", "av1-1-b8-01-size-198x198.ivf", - "av1-1-b8-01-size-198x200.ivf", "av1-1-b8-01-size-198x202.ivf", - "av1-1-b8-01-size-198x208.ivf", "av1-1-b8-01-size-198x210.ivf", - "av1-1-b8-01-size-198x224.ivf", "av1-1-b8-01-size-198x226.ivf", - "av1-1-b8-01-size-200x196.ivf", "av1-1-b8-01-size-200x198.ivf", - "av1-1-b8-01-size-200x200.ivf", "av1-1-b8-01-size-200x202.ivf", - "av1-1-b8-01-size-200x208.ivf", "av1-1-b8-01-size-200x210.ivf", - "av1-1-b8-01-size-200x224.ivf", "av1-1-b8-01-size-200x226.ivf", - "av1-1-b8-01-size-202x196.ivf", "av1-1-b8-01-size-202x198.ivf", - "av1-1-b8-01-size-202x200.ivf", "av1-1-b8-01-size-202x202.ivf", - "av1-1-b8-01-size-202x208.ivf", "av1-1-b8-01-size-202x210.ivf", - "av1-1-b8-01-size-202x224.ivf", "av1-1-b8-01-size-202x226.ivf", - "av1-1-b8-01-size-208x196.ivf", "av1-1-b8-01-size-208x198.ivf", - "av1-1-b8-01-size-208x200.ivf", "av1-1-b8-01-size-208x202.ivf", - "av1-1-b8-01-size-208x208.ivf", "av1-1-b8-01-size-208x210.ivf", - "av1-1-b8-01-size-208x224.ivf", "av1-1-b8-01-size-208x226.ivf", - "av1-1-b8-01-size-210x196.ivf", "av1-1-b8-01-size-210x198.ivf", - "av1-1-b8-01-size-210x200.ivf", "av1-1-b8-01-size-210x202.ivf", - "av1-1-b8-01-size-210x208.ivf", "av1-1-b8-01-size-210x210.ivf", - "av1-1-b8-01-size-210x224.ivf", "av1-1-b8-01-size-210x226.ivf", - "av1-1-b8-01-size-224x196.ivf", "av1-1-b8-01-size-224x198.ivf", - "av1-1-b8-01-size-224x200.ivf", "av1-1-b8-01-size-224x202.ivf", - "av1-1-b8-01-size-224x208.ivf", "av1-1-b8-01-size-224x210.ivf", - "av1-1-b8-01-size-224x224.ivf", "av1-1-b8-01-size-224x226.ivf", - "av1-1-b8-01-size-226x196.ivf", "av1-1-b8-01-size-226x198.ivf", - "av1-1-b8-01-size-226x200.ivf", "av1-1-b8-01-size-226x202.ivf", - "av1-1-b8-01-size-226x208.ivf", "av1-1-b8-01-size-226x210.ivf", - "av1-1-b8-01-size-226x224.ivf", "av1-1-b8-01-size-226x226.ivf", - "av1-1-b8-01-size-32x16.ivf", "av1-1-b8-01-size-32x18.ivf", - "av1-1-b8-01-size-32x32.ivf", "av1-1-b8-01-size-32x34.ivf", - "av1-1-b8-01-size-32x64.ivf", "av1-1-b8-01-size-32x66.ivf", - "av1-1-b8-01-size-34x16.ivf", "av1-1-b8-01-size-34x18.ivf", - "av1-1-b8-01-size-34x32.ivf", "av1-1-b8-01-size-34x34.ivf", - "av1-1-b8-01-size-34x64.ivf", "av1-1-b8-01-size-34x66.ivf", - "av1-1-b8-01-size-64x16.ivf", "av1-1-b8-01-size-64x18.ivf", - "av1-1-b8-01-size-64x32.ivf", "av1-1-b8-01-size-64x34.ivf", - "av1-1-b8-01-size-64x64.ivf", "av1-1-b8-01-size-64x66.ivf", - "av1-1-b8-01-size-66x16.ivf", "av1-1-b8-01-size-66x18.ivf", - "av1-1-b8-01-size-66x32.ivf", "av1-1-b8-01-size-66x34.ivf", - "av1-1-b8-01-size-66x64.ivf", "av1-1-b8-01-size-66x66.ivf", - "av1-1-b8-02-allintra.ivf", "av1-1-b8-03-sizedown.mkv", - "av1-1-b8-03-sizeup.mkv", "av1-1-b8-22-svc-L1T2.ivf", - "av1-1-b8-22-svc-L2T1.ivf", "av1-1-b8-22-svc-L2T2.ivf" -}; +const char *const kAV1TestVectors[] = { "av1-1-b8-00-quantizer-00.ivf", + "av1-1-b8-00-quantizer-01.ivf", + "av1-1-b8-00-quantizer-02.ivf", + "av1-1-b8-00-quantizer-03.ivf", + "av1-1-b8-00-quantizer-04.ivf", + "av1-1-b8-00-quantizer-05.ivf", + "av1-1-b8-00-quantizer-06.ivf", + "av1-1-b8-00-quantizer-07.ivf", + "av1-1-b8-00-quantizer-08.ivf", + "av1-1-b8-00-quantizer-09.ivf", + "av1-1-b8-00-quantizer-10.ivf", + "av1-1-b8-00-quantizer-11.ivf", + "av1-1-b8-00-quantizer-12.ivf", + "av1-1-b8-00-quantizer-13.ivf", + "av1-1-b8-00-quantizer-14.ivf", + "av1-1-b8-00-quantizer-15.ivf", + "av1-1-b8-00-quantizer-16.ivf", + "av1-1-b8-00-quantizer-17.ivf", + "av1-1-b8-00-quantizer-18.ivf", + "av1-1-b8-00-quantizer-19.ivf", + "av1-1-b8-00-quantizer-20.ivf", + "av1-1-b8-00-quantizer-21.ivf", + "av1-1-b8-00-quantizer-22.ivf", + "av1-1-b8-00-quantizer-23.ivf", + "av1-1-b8-00-quantizer-24.ivf", + "av1-1-b8-00-quantizer-25.ivf", + "av1-1-b8-00-quantizer-26.ivf", + "av1-1-b8-00-quantizer-27.ivf", + "av1-1-b8-00-quantizer-28.ivf", + "av1-1-b8-00-quantizer-29.ivf", + "av1-1-b8-00-quantizer-30.ivf", + "av1-1-b8-00-quantizer-31.ivf", + "av1-1-b8-00-quantizer-32.ivf", + "av1-1-b8-00-quantizer-33.ivf", + "av1-1-b8-00-quantizer-34.ivf", + "av1-1-b8-00-quantizer-35.ivf", + "av1-1-b8-00-quantizer-36.ivf", + "av1-1-b8-00-quantizer-37.ivf", + "av1-1-b8-00-quantizer-38.ivf", + "av1-1-b8-00-quantizer-39.ivf", + "av1-1-b8-00-quantizer-40.ivf", + "av1-1-b8-00-quantizer-41.ivf", + "av1-1-b8-00-quantizer-42.ivf", + "av1-1-b8-00-quantizer-43.ivf", + "av1-1-b8-00-quantizer-44.ivf", + "av1-1-b8-00-quantizer-45.ivf", + "av1-1-b8-00-quantizer-46.ivf", + "av1-1-b8-00-quantizer-47.ivf", + "av1-1-b8-00-quantizer-48.ivf", + "av1-1-b8-00-quantizer-49.ivf", + "av1-1-b8-00-quantizer-50.ivf", + "av1-1-b8-00-quantizer-51.ivf", + "av1-1-b8-00-quantizer-52.ivf", + "av1-1-b8-00-quantizer-53.ivf", + "av1-1-b8-00-quantizer-54.ivf", + "av1-1-b8-00-quantizer-55.ivf", + "av1-1-b8-00-quantizer-56.ivf", + "av1-1-b8-00-quantizer-57.ivf", + "av1-1-b8-00-quantizer-58.ivf", + "av1-1-b8-00-quantizer-59.ivf", + "av1-1-b8-00-quantizer-60.ivf", + "av1-1-b8-00-quantizer-61.ivf", + "av1-1-b8-00-quantizer-62.ivf", + "av1-1-b8-00-quantizer-63.ivf", + "av1-1-b10-00-quantizer-00.ivf", + "av1-1-b10-00-quantizer-01.ivf", + "av1-1-b10-00-quantizer-02.ivf", + "av1-1-b10-00-quantizer-03.ivf", + "av1-1-b10-00-quantizer-04.ivf", + "av1-1-b10-00-quantizer-05.ivf", + "av1-1-b10-00-quantizer-06.ivf", + "av1-1-b10-00-quantizer-07.ivf", + "av1-1-b10-00-quantizer-08.ivf", + "av1-1-b10-00-quantizer-09.ivf", + "av1-1-b10-00-quantizer-10.ivf", + "av1-1-b10-00-quantizer-11.ivf", + "av1-1-b10-00-quantizer-12.ivf", + "av1-1-b10-00-quantizer-13.ivf", + "av1-1-b10-00-quantizer-14.ivf", + "av1-1-b10-00-quantizer-15.ivf", + "av1-1-b10-00-quantizer-16.ivf", + "av1-1-b10-00-quantizer-17.ivf", + "av1-1-b10-00-quantizer-18.ivf", + "av1-1-b10-00-quantizer-19.ivf", + "av1-1-b10-00-quantizer-20.ivf", + "av1-1-b10-00-quantizer-21.ivf", + "av1-1-b10-00-quantizer-22.ivf", + "av1-1-b10-00-quantizer-23.ivf", + "av1-1-b10-00-quantizer-24.ivf", + "av1-1-b10-00-quantizer-25.ivf", + "av1-1-b10-00-quantizer-26.ivf", + "av1-1-b10-00-quantizer-27.ivf", + "av1-1-b10-00-quantizer-28.ivf", + "av1-1-b10-00-quantizer-29.ivf", + "av1-1-b10-00-quantizer-30.ivf", + "av1-1-b10-00-quantizer-31.ivf", + "av1-1-b10-00-quantizer-32.ivf", + "av1-1-b10-00-quantizer-33.ivf", + "av1-1-b10-00-quantizer-34.ivf", + "av1-1-b10-00-quantizer-35.ivf", + "av1-1-b10-00-quantizer-36.ivf", + "av1-1-b10-00-quantizer-37.ivf", + "av1-1-b10-00-quantizer-38.ivf", + "av1-1-b10-00-quantizer-39.ivf", + "av1-1-b10-00-quantizer-40.ivf", + "av1-1-b10-00-quantizer-41.ivf", + "av1-1-b10-00-quantizer-42.ivf", + "av1-1-b10-00-quantizer-43.ivf", + "av1-1-b10-00-quantizer-44.ivf", + "av1-1-b10-00-quantizer-45.ivf", + "av1-1-b10-00-quantizer-46.ivf", + "av1-1-b10-00-quantizer-47.ivf", + "av1-1-b10-00-quantizer-48.ivf", + "av1-1-b10-00-quantizer-49.ivf", + "av1-1-b10-00-quantizer-50.ivf", + "av1-1-b10-00-quantizer-51.ivf", + "av1-1-b10-00-quantizer-52.ivf", + "av1-1-b10-00-quantizer-53.ivf", + "av1-1-b10-00-quantizer-54.ivf", + "av1-1-b10-00-quantizer-55.ivf", + "av1-1-b10-00-quantizer-56.ivf", + "av1-1-b10-00-quantizer-57.ivf", + "av1-1-b10-00-quantizer-58.ivf", + "av1-1-b10-00-quantizer-59.ivf", + "av1-1-b10-00-quantizer-60.ivf", + "av1-1-b10-00-quantizer-61.ivf", + "av1-1-b10-00-quantizer-62.ivf", + "av1-1-b10-00-quantizer-63.ivf", + "av1-1-b8-01-size-16x16.ivf", + "av1-1-b8-01-size-16x18.ivf", + "av1-1-b8-01-size-16x32.ivf", + "av1-1-b8-01-size-16x34.ivf", + "av1-1-b8-01-size-16x64.ivf", + "av1-1-b8-01-size-16x66.ivf", + "av1-1-b8-01-size-18x16.ivf", + "av1-1-b8-01-size-18x18.ivf", + "av1-1-b8-01-size-18x32.ivf", + "av1-1-b8-01-size-18x34.ivf", + "av1-1-b8-01-size-18x64.ivf", + "av1-1-b8-01-size-18x66.ivf", + "av1-1-b8-01-size-196x196.ivf", + "av1-1-b8-01-size-196x198.ivf", + "av1-1-b8-01-size-196x200.ivf", + "av1-1-b8-01-size-196x202.ivf", + "av1-1-b8-01-size-196x208.ivf", + "av1-1-b8-01-size-196x210.ivf", + "av1-1-b8-01-size-196x224.ivf", + "av1-1-b8-01-size-196x226.ivf", + "av1-1-b8-01-size-198x196.ivf", + "av1-1-b8-01-size-198x198.ivf", + "av1-1-b8-01-size-198x200.ivf", + "av1-1-b8-01-size-198x202.ivf", + "av1-1-b8-01-size-198x208.ivf", + "av1-1-b8-01-size-198x210.ivf", + "av1-1-b8-01-size-198x224.ivf", + "av1-1-b8-01-size-198x226.ivf", + "av1-1-b8-01-size-200x196.ivf", + "av1-1-b8-01-size-200x198.ivf", + "av1-1-b8-01-size-200x200.ivf", + "av1-1-b8-01-size-200x202.ivf", + "av1-1-b8-01-size-200x208.ivf", + "av1-1-b8-01-size-200x210.ivf", + "av1-1-b8-01-size-200x224.ivf", + "av1-1-b8-01-size-200x226.ivf", + "av1-1-b8-01-size-202x196.ivf", + "av1-1-b8-01-size-202x198.ivf", + "av1-1-b8-01-size-202x200.ivf", + "av1-1-b8-01-size-202x202.ivf", + "av1-1-b8-01-size-202x208.ivf", + "av1-1-b8-01-size-202x210.ivf", + "av1-1-b8-01-size-202x224.ivf", + "av1-1-b8-01-size-202x226.ivf", + "av1-1-b8-01-size-208x196.ivf", + "av1-1-b8-01-size-208x198.ivf", + "av1-1-b8-01-size-208x200.ivf", + "av1-1-b8-01-size-208x202.ivf", + "av1-1-b8-01-size-208x208.ivf", + "av1-1-b8-01-size-208x210.ivf", + "av1-1-b8-01-size-208x224.ivf", + "av1-1-b8-01-size-208x226.ivf", + "av1-1-b8-01-size-210x196.ivf", + "av1-1-b8-01-size-210x198.ivf", + "av1-1-b8-01-size-210x200.ivf", + "av1-1-b8-01-size-210x202.ivf", + "av1-1-b8-01-size-210x208.ivf", + "av1-1-b8-01-size-210x210.ivf", + "av1-1-b8-01-size-210x224.ivf", + "av1-1-b8-01-size-210x226.ivf", + "av1-1-b8-01-size-224x196.ivf", + "av1-1-b8-01-size-224x198.ivf", + "av1-1-b8-01-size-224x200.ivf", + "av1-1-b8-01-size-224x202.ivf", + "av1-1-b8-01-size-224x208.ivf", + "av1-1-b8-01-size-224x210.ivf", + "av1-1-b8-01-size-224x224.ivf", + "av1-1-b8-01-size-224x226.ivf", + "av1-1-b8-01-size-226x196.ivf", + "av1-1-b8-01-size-226x198.ivf", + "av1-1-b8-01-size-226x200.ivf", + "av1-1-b8-01-size-226x202.ivf", + "av1-1-b8-01-size-226x208.ivf", + "av1-1-b8-01-size-226x210.ivf", + "av1-1-b8-01-size-226x224.ivf", + "av1-1-b8-01-size-226x226.ivf", + "av1-1-b8-01-size-32x16.ivf", + "av1-1-b8-01-size-32x18.ivf", + "av1-1-b8-01-size-32x32.ivf", + "av1-1-b8-01-size-32x34.ivf", + "av1-1-b8-01-size-32x64.ivf", + "av1-1-b8-01-size-32x66.ivf", + "av1-1-b8-01-size-34x16.ivf", + "av1-1-b8-01-size-34x18.ivf", + "av1-1-b8-01-size-34x32.ivf", + "av1-1-b8-01-size-34x34.ivf", + "av1-1-b8-01-size-34x64.ivf", + "av1-1-b8-01-size-34x66.ivf", + "av1-1-b8-01-size-64x16.ivf", + "av1-1-b8-01-size-64x18.ivf", + "av1-1-b8-01-size-64x32.ivf", + "av1-1-b8-01-size-64x34.ivf", + "av1-1-b8-01-size-64x64.ivf", + "av1-1-b8-01-size-64x66.ivf", + "av1-1-b8-01-size-66x16.ivf", + "av1-1-b8-01-size-66x18.ivf", + "av1-1-b8-01-size-66x32.ivf", + "av1-1-b8-01-size-66x34.ivf", + "av1-1-b8-01-size-66x64.ivf", + "av1-1-b8-01-size-66x66.ivf", + "av1-1-b8-02-allintra.ivf", + "av1-1-b8-03-sizedown.mkv", + "av1-1-b8-03-sizeup.mkv", + "av1-1-b8-04-cdfupdate.ivf", + "av1-1-b8-05-mv.ivf", + "av1-1-b8-06-mfmv.ivf", + "av1-1-b8-22-svc-L1T2.ivf", + "av1-1-b8-22-svc-L2T1.ivf", + "av1-1-b8-22-svc-L2T2.ivf" }; const int kNumAV1TestVectors = NELEMENTS(kAV1TestVectors); #endif // CONFIG_AV1_DECODER diff --git a/third_party/aom/test/variance_test.cc b/third_party/aom/test/variance_test.cc index d57fef99a1..1942de014f 100644 --- a/third_party/aom/test/variance_test.cc +++ b/third_party/aom/test/variance_test.cc @@ -703,6 +703,7 @@ class SubpelVarianceTest protected: void RefTest(); void ExtremeRefTest(); + void SpeedTest(); ACMRandom rnd_; uint8_t *src_; @@ -785,6 +786,41 @@ void SubpelVarianceTest::ExtremeRefTest() { } } +template +void SubpelVarianceTest::SpeedTest() { + if (!use_high_bit_depth()) { + for (int j = 0; j < block_size(); j++) { + src_[j] = rnd_.Rand8(); + } + for (int j = 0; j < block_size() + width() + height() + 1; j++) { + ref_[j] = rnd_.Rand8(); + } + } else { + for (int j = 0; j < block_size(); j++) { + CONVERT_TO_SHORTPTR(src_)[j] = rnd_.Rand16() & mask(); + } + for (int j = 0; j < block_size() + width() + height() + 1; j++) { + CONVERT_TO_SHORTPTR(ref_)[j] = rnd_.Rand16() & mask(); + } + } + + unsigned int sse1; + int run_time = 1000000000 / block_size(); + aom_usec_timer timer; + + aom_usec_timer_start(&timer); + for (int i = 0; i < run_time; ++i) { + int x = rnd_(8); + int y = rnd_(8); + params_.func(ref_, width() + 1, x, y, src_, width(), &sse1); + } + aom_usec_timer_mark(&timer); + + const int elapsed_time = static_cast(aom_usec_timer_elapsed(&timer)); + printf("sub_pixel_variance_%dx%d_%d: %d us\n", width(), height(), + params_.bit_depth, elapsed_time); +} + template <> void SubpelVarianceTest::RefTest() { for (int x = 0; x < 8; ++x) { @@ -1188,6 +1224,7 @@ TEST_P(AvxHBDVarianceTest, OneQuarter) { OneQuarterTest(); } TEST_P(AvxHBDVarianceTest, DISABLED_Speed) { SpeedTest(); } TEST_P(AvxHBDSubpelVarianceTest, Ref) { RefTest(); } TEST_P(AvxHBDSubpelVarianceTest, ExtremeRef) { ExtremeRefTest(); } +TEST_P(AvxHBDSubpelVarianceTest, DISABLED_Speed) { SpeedTest(); } TEST_P(AvxHBDSubpelAvgVarianceTest, Ref) { RefTest(); } /* TODO(debargha): This test does not support the highbd version @@ -1677,6 +1714,9 @@ INSTANTIATE_TEST_CASE_P(AVX2, AvxHBDVarianceTest, #endif // HAVE_AVX2 const SubpelVarianceParams kArrayHBDSubpelVariance_sse2[] = { + SubpelVarianceParams(7, 7, &aom_highbd_12_sub_pixel_variance128x128_sse2, 12), + SubpelVarianceParams(7, 6, &aom_highbd_12_sub_pixel_variance128x64_sse2, 12), + SubpelVarianceParams(6, 7, &aom_highbd_12_sub_pixel_variance64x128_sse2, 12), SubpelVarianceParams(6, 6, &aom_highbd_12_sub_pixel_variance64x64_sse2, 12), SubpelVarianceParams(6, 5, &aom_highbd_12_sub_pixel_variance64x32_sse2, 12), SubpelVarianceParams(5, 6, &aom_highbd_12_sub_pixel_variance32x64_sse2, 12), @@ -1688,6 +1728,9 @@ const SubpelVarianceParams kArrayHBDSubpelVariance_sse2[] = { SubpelVarianceParams(3, 4, &aom_highbd_12_sub_pixel_variance8x16_sse2, 12), SubpelVarianceParams(3, 3, &aom_highbd_12_sub_pixel_variance8x8_sse2, 12), SubpelVarianceParams(3, 2, &aom_highbd_12_sub_pixel_variance8x4_sse2, 12), + SubpelVarianceParams(7, 7, &aom_highbd_10_sub_pixel_variance128x128_sse2, 10), + SubpelVarianceParams(7, 6, &aom_highbd_10_sub_pixel_variance128x64_sse2, 10), + SubpelVarianceParams(6, 7, &aom_highbd_10_sub_pixel_variance64x128_sse2, 10), SubpelVarianceParams(6, 6, &aom_highbd_10_sub_pixel_variance64x64_sse2, 10), SubpelVarianceParams(6, 5, &aom_highbd_10_sub_pixel_variance64x32_sse2, 10), SubpelVarianceParams(5, 6, &aom_highbd_10_sub_pixel_variance32x64_sse2, 10), @@ -1699,6 +1742,9 @@ const SubpelVarianceParams kArrayHBDSubpelVariance_sse2[] = { SubpelVarianceParams(3, 4, &aom_highbd_10_sub_pixel_variance8x16_sse2, 10), SubpelVarianceParams(3, 3, &aom_highbd_10_sub_pixel_variance8x8_sse2, 10), SubpelVarianceParams(3, 2, &aom_highbd_10_sub_pixel_variance8x4_sse2, 10), + SubpelVarianceParams(7, 7, &aom_highbd_8_sub_pixel_variance128x128_sse2, 8), + SubpelVarianceParams(7, 6, &aom_highbd_8_sub_pixel_variance128x64_sse2, 8), + SubpelVarianceParams(6, 7, &aom_highbd_8_sub_pixel_variance64x128_sse2, 8), SubpelVarianceParams(6, 6, &aom_highbd_8_sub_pixel_variance64x64_sse2, 8), SubpelVarianceParams(6, 5, &aom_highbd_8_sub_pixel_variance64x32_sse2, 8), SubpelVarianceParams(5, 6, &aom_highbd_8_sub_pixel_variance32x64_sse2, 8), @@ -1711,7 +1757,6 @@ const SubpelVarianceParams kArrayHBDSubpelVariance_sse2[] = { SubpelVarianceParams(3, 3, &aom_highbd_8_sub_pixel_variance8x8_sse2, 8), SubpelVarianceParams(3, 2, &aom_highbd_8_sub_pixel_variance8x4_sse2, 8) }; - INSTANTIATE_TEST_CASE_P(SSE2, AvxHBDSubpelVarianceTest, ::testing::ValuesIn(kArrayHBDSubpelVariance_sse2)); diff --git a/third_party/aom/test/yuv_temporal_filter_test.cc b/third_party/aom/test/yuv_temporal_filter_test.cc new file mode 100644 index 0000000000..fcaf0df8d0 --- /dev/null +++ b/third_party/aom/test/yuv_temporal_filter_test.cc @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2019, 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 "config/av1_rtcd.h" +#include "test/acm_random.h" +#include "test/register_state_check.h" +#include "aom_ports/aom_timer.h" +#include "aom_ports/mem.h" + +namespace { + +using ::libaom_test::ACMRandom; + +const int MAX_WIDTH = 32; +const int MAX_HEIGHT = 32; + +typedef void (*YUVTemporalFilterFunc)( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, + uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, + uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count); + +struct TemporalFilterWithBd { + TemporalFilterWithBd(YUVTemporalFilterFunc func, int bitdepth) + : temporal_filter(func), bd(bitdepth) {} + + YUVTemporalFilterFunc temporal_filter; + int bd; +}; + +std::ostream &operator<<(std::ostream &os, const TemporalFilterWithBd &tf) { + return os << "Bitdepth: " << tf.bd; +} + +int GetFilterWeight(unsigned int row, unsigned int col, + unsigned int block_height, unsigned int block_width, + const int *const blk_fw, int use_32x32) { + if (use_32x32) { + return blk_fw[0]; + } + + return blk_fw[2 * (row >= block_height / 2) + (col >= block_width / 2)]; +} + +template +int GetModIndex(int sum_dist, int index, int rounding, int strength, + int filter_weight) { + int mod = sum_dist * 3 / index; + mod += rounding; + mod >>= strength; + + mod = AOMMIN(16, mod); + + mod = 16 - mod; + mod *= filter_weight; + + return mod; +} + +// Lowbitdepth version +template <> +int GetModIndex(int sum_dist, int index, int rounding, int strength, + int filter_weight) { + unsigned int index_mult[14] = { + 0, 0, 0, 0, 49152, 39322, 32768, 28087, 24576, 21846, 19661, 17874, 0, 15124 + }; + + assert(index >= 0 && index <= 13); + assert(index_mult[index] != 0); + + int mod = (clamp(sum_dist, 0, UINT16_MAX) * index_mult[index]) >> 16; + mod += rounding; + mod >>= strength; + + mod = AOMMIN(16, mod); + + mod = 16 - mod; + mod *= filter_weight; + + return mod; +} + +// Highbitdepth version +template <> +int GetModIndex(int sum_dist, int index, int rounding, int strength, + int filter_weight) { + int64_t index_mult[14] = { 0U, 0U, 0U, 0U, + 3221225472U, 2576980378U, 2147483648U, 1840700270U, + 1610612736U, 1431655766U, 1288490189U, 1171354718U, + 0U, 991146300U }; + + assert(index >= 0 && index <= 13); + assert(index_mult[index] != 0); + + int mod = static_cast((sum_dist * index_mult[index]) >> 32); + mod += rounding; + mod >>= strength; + + mod = AOMMIN(16, mod); + + mod = 16 - mod; + mod *= filter_weight; + + return mod; +} + +template +void SetArray(PixelType *pixel_array, int width, int height, int stride, + int val) { + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + pixel_array[col] = val; + } + pixel_array += stride; + } +} + +template +void SetArray(PixelType *pixel_array, int width, int height, int stride, + ACMRandom *rnd, int low_val, int high_val) { + EXPECT_LE(low_val, high_val); + + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + const int val = + static_cast((*rnd).PseudoUniform(high_val - low_val)); + pixel_array[col] = low_val + val; + } + pixel_array += stride; + } +} + +template +bool CheckArrayEqual(const ValueType *arr_1, const ValueType *arr_2, int width, + int height, int stride_1, int stride_2) { + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + if (arr_1[col] != arr_2[col]) { + return false; + } + } + arr_1 += stride_1; + arr_2 += stride_2; + } + return true; +} + +template +void PrintArrayDiff(const ValueType *arr_1, const ValueType *arr_2, int width, + int height, int stride_1, int stride_2) { + const ValueType *arr_1_start = arr_1, *arr_2_start = arr_2; + + printf("Array 1:\n"); + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + if (arr_1[col] != arr_2[col]) { + printf("*%3d", arr_1[col]); + } else { + printf("%4d", arr_1[col]); + } + } + printf("\n"); + arr_1 += stride_1; + arr_2 += stride_2; + } + + arr_1 = arr_1_start; + arr_2 = arr_2_start; + + printf("Array 2:\n"); + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + if (arr_1[col] != arr_2[col]) { + printf("*%3d", arr_2[col]); + } else { + printf("%4d", arr_2[col]); + } + } + printf("\n"); + arr_1 += stride_1; + arr_2 += stride_2; + } + + arr_1 = arr_1_start; + arr_2 = arr_2_start; + printf("Difference:\n"); + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + printf("%4d", arr_1[col] - arr_2[col]); + } + printf("\n"); + arr_1 += stride_1; + arr_2 += stride_2; + } +} + +template +void ApplyReferenceFilter(const PixelType *y_src, const PixelType *y_pre, + const PixelType *u_src, const PixelType *v_src, + const PixelType *u_pre, const PixelType *v_pre, + unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, + const int *const blk_fw, int use_32x32, + uint32_t *y_accum, uint16_t *y_count, + uint32_t *u_accum, uint16_t *u_count, + uint32_t *v_accum, uint16_t *v_count) { + const int uv_block_width = block_width >> ss_x, + uv_block_height = block_height >> ss_y; + const int y_src_stride = block_width, y_pre_stride = block_width; + const int uv_src_stride = uv_block_width, uv_pre_stride = uv_block_width; + const int y_diff_stride = block_width, uv_diff_stride = uv_block_width; + const int y_count_stride = block_width, u_count_stride = uv_block_width, + v_count_stride = uv_block_width; + const int y_accum_stride = block_width, u_accum_stride = uv_block_width, + v_accum_stride = uv_block_width; + + int y_dif[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + int u_dif[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + int v_dif[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + + const int rounding = (1 << strength) >> 1; + + // Get the square diffs + for (int row = 0; row < (int)block_height; row++) { + for (int col = 0; col < (int)block_width; col++) { + const int diff = + y_src[row * y_src_stride + col] - y_pre[row * y_pre_stride + col]; + y_dif[row * y_diff_stride + col] = diff * diff; + } + } + + for (int row = 0; row < (int)uv_block_height; row++) { + for (int col = 0; col < (int)uv_block_width; col++) { + const int u_diff = + u_src[row * uv_src_stride + col] - u_pre[row * uv_pre_stride + col]; + const int v_diff = + v_src[row * uv_src_stride + col] - v_pre[row * uv_pre_stride + col]; + u_dif[row * uv_diff_stride + col] = u_diff * u_diff; + v_dif[row * uv_diff_stride + col] = v_diff * v_diff; + } + } + + // Apply the filter to luma + for (int row = 0; row < (int)block_height; row++) { + for (int col = 0; col < (int)block_width; col++) { + const int uv_row = row >> ss_y; + const int uv_col = col >> ss_x; + const int filter_weight = GetFilterWeight(row, col, block_height, + block_width, blk_fw, use_32x32); + + // First we get the modifier for the current y pixel + const int y_pixel = y_pre[row * y_pre_stride + col]; + int y_num_used = 0; + int y_mod = 0; + + // Sum the neighboring 3x3 y pixels + for (int row_step = -1; row_step <= 1; row_step++) { + for (int col_step = -1; col_step <= 1; col_step++) { + const int sub_row = row + row_step; + const int sub_col = col + col_step; + + if (sub_row >= 0 && sub_row < (int)block_height && sub_col >= 0 && + sub_col < (int)block_width) { + y_mod += y_dif[sub_row * y_diff_stride + sub_col]; + y_num_used++; + } + } + } + + // Sum the corresponding uv pixels to the current y modifier + // Note we are rounding down instead of rounding to the nearest pixel. + y_mod += u_dif[uv_row * uv_diff_stride + uv_col]; + y_mod += v_dif[uv_row * uv_diff_stride + uv_col]; + + y_num_used += 2; + + // Set the modifier + y_mod = GetModIndex(y_mod, y_num_used, rounding, strength, + filter_weight); + + // Accumulate the result + y_count[row * y_count_stride + col] += y_mod; + y_accum[row * y_accum_stride + col] += y_mod * y_pixel; + } + } + + // Apply the filter to chroma + for (int uv_row = 0; uv_row < (int)uv_block_height; uv_row++) { + for (int uv_col = 0; uv_col < (int)uv_block_width; uv_col++) { + const int y_row = uv_row << ss_y; + const int y_col = uv_col << ss_x; + const int filter_weight = GetFilterWeight( + uv_row, uv_col, uv_block_height, uv_block_width, blk_fw, use_32x32); + + const int u_pixel = u_pre[uv_row * uv_pre_stride + uv_col]; + const int v_pixel = v_pre[uv_row * uv_pre_stride + uv_col]; + + int uv_num_used = 0; + int u_mod = 0, v_mod = 0; + + // Sum the neighboring 3x3 chromal pixels to the chroma modifier + for (int row_step = -1; row_step <= 1; row_step++) { + for (int col_step = -1; col_step <= 1; col_step++) { + const int sub_row = uv_row + row_step; + const int sub_col = uv_col + col_step; + + if (sub_row >= 0 && sub_row < uv_block_height && sub_col >= 0 && + sub_col < uv_block_width) { + u_mod += u_dif[sub_row * uv_diff_stride + sub_col]; + v_mod += v_dif[sub_row * uv_diff_stride + sub_col]; + uv_num_used++; + } + } + } + + // Sum all the luma pixels associated with the current luma pixel + for (int row_step = 0; row_step < 1 + ss_y; row_step++) { + for (int col_step = 0; col_step < 1 + ss_x; col_step++) { + const int sub_row = y_row + row_step; + const int sub_col = y_col + col_step; + const int y_diff = y_dif[sub_row * y_diff_stride + sub_col]; + + u_mod += y_diff; + v_mod += y_diff; + uv_num_used++; + } + } + + // Set the modifier + u_mod = GetModIndex(u_mod, uv_num_used, rounding, strength, + filter_weight); + v_mod = GetModIndex(v_mod, uv_num_used, rounding, strength, + filter_weight); + + // Accumulate the result + u_count[uv_row * u_count_stride + uv_col] += u_mod; + u_accum[uv_row * u_accum_stride + uv_col] += u_mod * u_pixel; + v_count[uv_row * v_count_stride + uv_col] += v_mod; + v_accum[uv_row * v_accum_stride + uv_col] += v_mod * v_pixel; + } + } +} + +class YUVTemporalFilterTest + : public ::testing::TestWithParam { + public: + virtual void SetUp() { + filter_func_ = GetParam().temporal_filter; + bd_ = GetParam().bd; + use_highbd_ = (bd_ != 8); + + rnd_.Reset(ACMRandom::DeterministicSeed()); + saturate_test_ = 0; + num_repeats_ = 10; + + ASSERT_TRUE(bd_ == 8 || bd_ == 10 || bd_ == 12); + } + + protected: + template + void CompareTestWithParam(int width, int height, int ss_x, int ss_y, + int filter_strength, int use_32x32, + const int *filter_weight); + template + void RunTestFilterWithParam(int width, int height, int ss_x, int ss_y, + int filter_strength, int use_32x32, + const int *filter_weight); + template + void ApplyTestFilter(const PixelType *y_src, int y_src_stride, + const PixelType *y_pre, int y_pre_stride, + const PixelType *u_src, const PixelType *v_src, + int uv_src_stride, const PixelType *u_pre, + const PixelType *v_pre, int uv_pre_stride, + unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, + int use_32x32, uint32_t *y_accum, uint16_t *y_count, + uint32_t *u_accumu, uint16_t *u_count, uint32_t *v_accum, + uint16_t *v_count); + + YUVTemporalFilterFunc filter_func_; + ACMRandom rnd_; + int saturate_test_; + int num_repeats_; + int use_highbd_; + int bd_; +}; + +template <> +void YUVTemporalFilterTest::ApplyTestFilter( + const uint8_t *y_src, int y_src_stride, const uint8_t *y_pre, + int y_pre_stride, const uint8_t *u_src, const uint8_t *v_src, + int uv_src_stride, const uint8_t *u_pre, const uint8_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, + uint32_t *y_accum, uint16_t *y_count, uint32_t *u_accum, uint16_t *u_count, + uint32_t *v_accum, uint16_t *v_count) { + ASM_REGISTER_STATE_CHECK( + filter_func_(y_src, y_src_stride, y_pre, y_pre_stride, u_src, v_src, + uv_src_stride, u_pre, v_pre, uv_pre_stride, block_width, + block_height, ss_x, ss_y, strength, blk_fw, use_32x32, + y_accum, y_count, u_accum, u_count, v_accum, v_count)); +} + +template <> +void YUVTemporalFilterTest::ApplyTestFilter( + const uint16_t *y_src, int y_src_stride, const uint16_t *y_pre, + int y_pre_stride, const uint16_t *u_src, const uint16_t *v_src, + int uv_src_stride, const uint16_t *u_pre, const uint16_t *v_pre, + int uv_pre_stride, unsigned int block_width, unsigned int block_height, + int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, + uint32_t *y_accum, uint16_t *y_count, uint32_t *u_accum, uint16_t *u_count, + uint32_t *v_accum, uint16_t *v_count) { + ASM_REGISTER_STATE_CHECK(filter_func_( + CONVERT_TO_BYTEPTR(y_src), y_src_stride, CONVERT_TO_BYTEPTR(y_pre), + y_pre_stride, CONVERT_TO_BYTEPTR(u_src), CONVERT_TO_BYTEPTR(v_src), + uv_src_stride, CONVERT_TO_BYTEPTR(u_pre), CONVERT_TO_BYTEPTR(v_pre), + uv_pre_stride, block_width, block_height, ss_x, ss_y, strength, blk_fw, + use_32x32, y_accum, y_count, u_accum, u_count, v_accum, v_count)); +} + +template +void YUVTemporalFilterTest::CompareTestWithParam(int width, int height, + int ss_x, int ss_y, + int filter_strength, + int use_32x32, + const int *filter_weight) { + const int uv_width = width >> ss_x, uv_height = height >> ss_y; + const int y_stride = width, uv_stride = uv_width; + + DECLARE_ALIGNED(16, PixelType, y_src[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, PixelType, y_pre[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, y_count_ref[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, y_accum_ref[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, y_count_tst[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, y_accum_tst[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + + DECLARE_ALIGNED(16, PixelType, u_src[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, PixelType, u_pre[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, u_count_ref[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, u_accum_ref[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, u_count_tst[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, u_accum_tst[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + + DECLARE_ALIGNED(16, PixelType, v_src[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, PixelType, v_pre[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, v_count_ref[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, v_accum_ref[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint16_t, v_count_tst[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + DECLARE_ALIGNED(16, uint32_t, v_accum_tst[MAX_WIDTH * MAX_HEIGHT]) = { 0 }; + + for (int repeats = 0; repeats < num_repeats_; repeats++) { + if (saturate_test_) { + const int max_val = (1 << bd_) - 1; + SetArray(y_src, width, height, y_stride, max_val); + SetArray(y_pre, width, height, y_stride, 0); + SetArray(u_src, uv_width, uv_height, uv_stride, max_val); + SetArray(u_pre, uv_width, uv_height, uv_stride, 0); + SetArray(v_src, uv_width, uv_height, uv_stride, max_val); + SetArray(v_pre, uv_width, uv_height, uv_stride, 0); + } else { + const int max_val = 7 << (bd_ - 8); + SetArray(y_src, width, height, y_stride, &rnd_, 0, max_val); + SetArray(y_pre, width, height, y_stride, &rnd_, 0, max_val); + SetArray(u_src, uv_width, uv_height, uv_stride, &rnd_, 0, max_val); + SetArray(u_pre, uv_width, uv_height, uv_stride, &rnd_, 0, max_val); + SetArray(v_src, uv_width, uv_height, uv_stride, &rnd_, 0, max_val); + SetArray(v_pre, uv_width, uv_height, uv_stride, &rnd_, 0, max_val); + } + + ApplyReferenceFilter( + y_src, y_pre, u_src, v_src, u_pre, v_pre, width, height, ss_x, ss_y, + filter_strength, filter_weight, use_32x32, y_accum_ref, y_count_ref, + u_accum_ref, u_count_ref, v_accum_ref, v_count_ref); + + ApplyTestFilter(y_src, y_stride, y_pre, y_stride, u_src, v_src, uv_stride, + u_pre, v_pre, uv_stride, width, height, ss_x, ss_y, + filter_strength, filter_weight, use_32x32, y_accum_tst, + y_count_tst, u_accum_tst, u_count_tst, v_accum_tst, + v_count_tst); + + EXPECT_TRUE(CheckArrayEqual(y_accum_tst, y_accum_ref, width, height, + y_stride, y_stride)); + EXPECT_TRUE(CheckArrayEqual(y_count_tst, y_count_ref, width, height, + y_stride, y_stride)); + EXPECT_TRUE(CheckArrayEqual(u_accum_tst, u_accum_ref, uv_width, uv_height, + uv_stride, uv_stride)); + EXPECT_TRUE(CheckArrayEqual(u_count_tst, u_count_ref, uv_width, uv_height, + uv_stride, uv_stride)); + EXPECT_TRUE(CheckArrayEqual(v_accum_tst, v_accum_ref, uv_width, uv_height, + uv_stride, uv_stride)); + EXPECT_TRUE(CheckArrayEqual(v_count_tst, v_count_ref, uv_width, uv_height, + uv_stride, uv_stride)); + + if (HasFailure()) { + if (use_32x32) { + printf("SS_X: %d, SS_Y: %d, Strength: %d, Weight: %d\n", ss_x, ss_y, + filter_strength, *filter_weight); + } else { + printf("SS_X: %d, SS_Y: %d, Strength: %d, Weights: %d,%d,%d,%d\n", ss_x, + ss_y, filter_strength, filter_weight[0], filter_weight[1], + filter_weight[2], filter_weight[3]); + } + + PrintArrayDiff(y_accum_ref, y_accum_tst, width, height, y_stride, + y_stride); + PrintArrayDiff(y_count_ref, y_count_tst, width, height, y_stride, + y_stride); + PrintArrayDiff(u_accum_ref, v_accum_tst, uv_width, uv_height, uv_stride, + uv_stride); + PrintArrayDiff(u_count_ref, v_count_tst, uv_width, uv_height, uv_stride, + uv_stride); + PrintArrayDiff(u_accum_ref, v_accum_tst, uv_width, uv_height, uv_stride, + uv_stride); + PrintArrayDiff(u_count_ref, v_count_tst, uv_width, uv_height, uv_stride, + uv_stride); + + return; + } + } +} + +template +void YUVTemporalFilterTest::RunTestFilterWithParam(int width, int height, + int ss_x, int ss_y, + int filter_strength, + int use_32x32, + const int *filter_weight) { + PixelType y_src[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + PixelType y_pre[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + uint16_t y_count[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + uint32_t y_accum[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + + PixelType u_src[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + PixelType u_pre[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + uint16_t u_count[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + uint32_t u_accum[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + + PixelType v_src[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + PixelType v_pre[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + uint16_t v_count[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + uint32_t v_accum[MAX_WIDTH * MAX_HEIGHT] = { 0 }; + + SetArray(y_src, width, height, MAX_WIDTH, &rnd_, 0, 7 << (bd_ = 8)); + SetArray(y_pre, width, height, MAX_WIDTH, &rnd_, 0, 7 << (bd_ = 8)); + SetArray(u_src, width, height, MAX_WIDTH, &rnd_, 0, 7 << (bd_ = 8)); + SetArray(u_pre, width, height, MAX_WIDTH, &rnd_, 0, 7 << (bd_ = 8)); + SetArray(v_src, width, height, MAX_WIDTH, &rnd_, 0, 7 << (bd_ = 8)); + SetArray(v_pre, width, height, MAX_WIDTH, &rnd_, 0, 7 << (bd_ = 8)); + + for (int repeats = 0; repeats < num_repeats_; repeats++) { + ApplyTestFilter(y_src, MAX_WIDTH, y_pre, MAX_WIDTH, u_src, v_src, MAX_WIDTH, + u_pre, v_pre, MAX_WIDTH, width, height, ss_x, ss_y, + filter_strength, filter_weight, use_32x32, y_accum, y_count, + u_accum, u_count, v_accum, v_count); + } +} + +TEST_P(YUVTemporalFilterTest, Use32x32) { + const int width = 32, height = 32; + const int use_32x32 = 1; + + for (int ss_x = 0; ss_x <= 1; ss_x++) { + for (int ss_y = 0; ss_y <= 1; ss_y++) { + for (int filter_strength = 0; filter_strength <= 6; + filter_strength += 2) { + for (int filter_weight = 0; filter_weight <= 2; filter_weight++) { + if (use_highbd_) { + const int adjusted_strength = filter_strength + 2 * (bd_ - 8); + CompareTestWithParam(width, height, ss_x, ss_y, + adjusted_strength, use_32x32, + &filter_weight); + } else { + CompareTestWithParam(width, height, ss_x, ss_y, + filter_strength, use_32x32, + &filter_weight); + } + ASSERT_FALSE(HasFailure()); + } + } + } + } +} + +TEST_P(YUVTemporalFilterTest, Use16x16) { + const int width = 32, height = 32; + const int use_32x32 = 0; + + for (int ss_x = 0; ss_x <= 1; ss_x++) { + for (int ss_y = 0; ss_y <= 1; ss_y++) { + for (int filter_idx = 0; filter_idx < 3 * 3 * 3 * 3; filter_idx++) { + // Set up the filter + int filter_weight[4]; + int filter_idx_cp = filter_idx; + for (int idx = 0; idx < 4; idx++) { + filter_weight[idx] = filter_idx_cp % 3; + filter_idx_cp /= 3; + } + + // Test each parameter + for (int filter_strength = 0; filter_strength <= 6; + filter_strength += 2) { + if (use_highbd_) { + const int adjusted_strength = filter_strength + 2 * (bd_ - 8); + CompareTestWithParam(width, height, ss_x, ss_y, + adjusted_strength, use_32x32, + filter_weight); + } else { + CompareTestWithParam(width, height, ss_x, ss_y, + filter_strength, use_32x32, + filter_weight); + } + + ASSERT_FALSE(HasFailure()); + } + } + } + } +} + +TEST_P(YUVTemporalFilterTest, SaturationTest) { + const int width = 32, height = 32; + const int use_32x32 = 1; + const int filter_weight = 1; + saturate_test_ = 1; + + for (int ss_x = 0; ss_x <= 1; ss_x++) { + for (int ss_y = 0; ss_y <= 1; ss_y++) { + for (int filter_strength = 0; filter_strength <= 6; + filter_strength += 2) { + if (use_highbd_) { + const int adjusted_strength = filter_strength + 2 * (bd_ - 8); + CompareTestWithParam(width, height, ss_x, ss_y, + adjusted_strength, use_32x32, + &filter_weight); + } else { + CompareTestWithParam(width, height, ss_x, ss_y, + filter_strength, use_32x32, + &filter_weight); + } + + ASSERT_FALSE(HasFailure()); + } + } + } +} + +TEST_P(YUVTemporalFilterTest, DISABLED_Speed) { + const int width = 32, height = 32; + num_repeats_ = 1000; + + for (int use_32x32 = 0; use_32x32 <= 1; use_32x32++) { + const int num_filter_weights = use_32x32 ? 3 : 3 * 3 * 3 * 3; + for (int ss_x = 0; ss_x <= 1; ss_x++) { + for (int ss_y = 0; ss_y <= 1; ss_y++) { + for (int filter_idx = 0; filter_idx < num_filter_weights; + filter_idx++) { + // Set up the filter + int filter_weight[4]; + int filter_idx_cp = filter_idx; + for (int idx = 0; idx < 4; idx++) { + filter_weight[idx] = filter_idx_cp % 3; + filter_idx_cp /= 3; + } + + // Test each parameter + for (int filter_strength = 0; filter_strength <= 6; + filter_strength += 2) { + aom_usec_timer timer; + aom_usec_timer_start(&timer); + + if (use_highbd_) { + RunTestFilterWithParam(width, height, ss_x, ss_y, + filter_strength, use_32x32, + filter_weight); + } else { + RunTestFilterWithParam(width, height, ss_x, ss_y, + filter_strength, use_32x32, + filter_weight); + } + + aom_usec_timer_mark(&timer); + const int elapsed_time = + static_cast(aom_usec_timer_elapsed(&timer)); + + printf( + "Bitdepth: %d, Use 32X32: %d, SS_X: %d, SS_Y: %d, Weight Idx: " + "%d, Strength: %d, Time: %5d\n", + bd_, use_32x32, ss_x, ss_y, filter_idx, filter_strength, + elapsed_time); + } + } + } + } + } +} + +INSTANTIATE_TEST_CASE_P( + C, YUVTemporalFilterTest, + ::testing::Values( + TemporalFilterWithBd(&av1_apply_temporal_filter_c, 8), + TemporalFilterWithBd(&av1_highbd_apply_temporal_filter_c, 10), + TemporalFilterWithBd(&av1_highbd_apply_temporal_filter_c, 12))); + +#if HAVE_SSE4_1 +INSTANTIATE_TEST_CASE_P( + SSE4_1, YUVTemporalFilterTest, + ::testing::Values( + TemporalFilterWithBd(&av1_apply_temporal_filter_sse4_1, 8), + TemporalFilterWithBd(&av1_highbd_apply_temporal_filter_sse4_1, 10), + TemporalFilterWithBd(&av1_highbd_apply_temporal_filter_sse4_1, 12))); +#endif // HAVE_SSE4_1 + +} // namespace